Skip to main content

modelio/
mesh_buffer.rs

1use std::ptr;
2
3use crate::error::{ModelIoError, Result};
4use crate::ffi;
5use crate::handle::ObjectHandle;
6use crate::mesh::MeshBuffer;
7use crate::types::MeshBufferType;
8use crate::util::required_handle;
9
10#[derive(Debug, Clone)]
11/// Wraps the corresponding Model I/O mesh buffer map counterpart.
12pub struct MeshBufferMap {
13    handle: ObjectHandle,
14    length: usize,
15}
16
17impl MeshBufferMap {
18    fn from_handle(handle: ObjectHandle, length: usize) -> Self {
19        Self { handle, length }
20    }
21
22    /// Returns the opaque pointer used to call the wrapped Model I/O mesh buffer map counterpart.
23    pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
24        self.handle.as_ptr()
25    }
26
27    #[must_use]
28    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer map counterpart.
29    pub fn length(&self) -> usize {
30        self.length
31    }
32
33    #[must_use]
34    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer map counterpart.
35    pub fn bytes(&self) -> Vec<u8> {
36        let mut bytes = vec![0_u8; self.length];
37        if bytes.is_empty() {
38            return bytes;
39        }
40        // SAFETY: The unsafe operation is valid in this context.
41        let written = unsafe {
42            ffi::mdl_mesh_buffer_map_copy_bytes(
43                self.as_ptr(),
44                self.length as u64,
45                bytes.as_mut_ptr(),
46                bytes.len() as u64,
47            )
48        } as usize;
49        bytes.truncate(written);
50        bytes
51    }
52
53    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer map counterpart.
54    pub fn write(&self, offset: usize, bytes: &[u8]) -> usize {
55        // SAFETY: The unsafe operation is valid in this context.
56        unsafe {
57            ffi::mdl_mesh_buffer_map_write_bytes(
58                self.as_ptr(),
59                self.length as u64,
60                bytes.as_ptr(),
61                bytes.len() as u64,
62                offset as u64,
63            ) as usize
64        }
65    }
66}
67
68#[derive(Debug, Clone)]
69/// Wraps the corresponding Model I/O mesh buffer allocator counterpart.
70pub struct MeshBufferAllocator {
71    handle: ObjectHandle,
72}
73
74impl MeshBufferAllocator {
75    /// Builds this wrapper from the retained handle of the wrapped Model I/O mesh buffer allocator counterpart.
76    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
77        Self { handle }
78    }
79
80    /// Returns the opaque pointer used to call the wrapped Model I/O mesh buffer allocator counterpart.
81    pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
82        self.handle.as_ptr()
83    }
84
85    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh buffer allocator counterpart.
86    pub fn new_zone(&self, capacity: usize) -> Result<MeshBufferZone> {
87        let mut out_zone = ptr::null_mut();
88        let mut out_error = ptr::null_mut();
89        // SAFETY: The unsafe operation is valid in this context.
90        let status = unsafe {
91            ffi::mdl_mesh_buffer_allocator_new_zone(
92                self.as_ptr(),
93                capacity as u64,
94                &mut out_zone,
95                &mut out_error,
96            )
97        };
98        crate::util::status_result(status, out_error)?;
99        Ok(MeshBufferZone::from_handle(required_handle(
100            out_zone,
101            "MDLMeshBufferZone",
102        )?))
103    }
104
105    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh buffer allocator counterpart.
106    pub fn new_zone_for_buffers(
107        &self,
108        sizes: &[usize],
109        types: &[MeshBufferType],
110    ) -> Result<MeshBufferZone> {
111        if sizes.len() != types.len() {
112            return Err(ModelIoError::new(
113                ffi::status::INVALID_ARGUMENT,
114                "mesh buffer sizes and types must have the same length",
115            ));
116        }
117        let raw_sizes = sizes.iter().map(|size| *size as u64).collect::<Vec<_>>();
118        let raw_types = types
119            .iter()
120            .map(|buffer_type| buffer_type.as_raw())
121            .collect::<Vec<_>>();
122        let mut out_zone = ptr::null_mut();
123        let mut out_error = ptr::null_mut();
124        // SAFETY: The unsafe operation is valid in this context.
125        let status = unsafe {
126            ffi::mdl_mesh_buffer_allocator_new_zone_for_buffers_with_size(
127                self.as_ptr(),
128                raw_sizes.as_ptr(),
129                raw_types.as_ptr(),
130                raw_sizes.len() as u64,
131                &mut out_zone,
132                &mut out_error,
133            )
134        };
135        crate::util::status_result(status, out_error)?;
136        Ok(MeshBufferZone::from_handle(required_handle(
137            out_zone,
138            "MDLMeshBufferZone",
139        )?))
140    }
141
142    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh buffer allocator counterpart.
143    pub fn new_buffer(&self, length: usize, buffer_type: MeshBufferType) -> Result<MeshBuffer> {
144        let mut out_buffer = ptr::null_mut();
145        let mut out_error = ptr::null_mut();
146        // SAFETY: The unsafe operation is valid in this context.
147        let status = unsafe {
148            ffi::mdl_mesh_buffer_allocator_new_buffer(
149                self.as_ptr(),
150                length as u64,
151                buffer_type.as_raw(),
152                &mut out_buffer,
153                &mut out_error,
154            )
155        };
156        crate::util::status_result(status, out_error)?;
157        Ok(MeshBuffer::from_handle(required_handle(
158            out_buffer,
159            "MDLMeshBuffer",
160        )?))
161    }
162
163    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh buffer allocator counterpart.
164    pub fn new_buffer_with_data(
165        &self,
166        data: &[u8],
167        buffer_type: MeshBufferType,
168    ) -> Result<MeshBuffer> {
169        let mut out_buffer = ptr::null_mut();
170        let mut out_error = ptr::null_mut();
171        // SAFETY: The unsafe operation is valid in this context.
172        let status = unsafe {
173            ffi::mdl_mesh_buffer_allocator_new_buffer_with_data(
174                self.as_ptr(),
175                data.as_ptr(),
176                data.len() as u64,
177                buffer_type.as_raw(),
178                &mut out_buffer,
179                &mut out_error,
180            )
181        };
182        crate::util::status_result(status, out_error)?;
183        Ok(MeshBuffer::from_handle(required_handle(
184            out_buffer,
185            "MDLMeshBuffer",
186        )?))
187    }
188
189    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh buffer allocator counterpart.
190    pub fn new_buffer_from_zone(
191        &self,
192        zone: Option<&MeshBufferZone>,
193        length: usize,
194        buffer_type: MeshBufferType,
195    ) -> Result<Option<MeshBuffer>> {
196        let mut out_buffer = ptr::null_mut();
197        let mut out_error = ptr::null_mut();
198        // SAFETY: The unsafe operation is valid in this context.
199        let status = unsafe {
200            ffi::mdl_mesh_buffer_allocator_new_buffer_from_zone_length(
201                self.as_ptr(),
202                zone.map_or(ptr::null_mut(), MeshBufferZone::as_ptr),
203                length as u64,
204                buffer_type.as_raw(),
205                &mut out_buffer,
206                &mut out_error,
207            )
208        };
209        crate::util::status_result(status, out_error)?;
210        // SAFETY: The unsafe operation is valid in this context.
211        Ok(unsafe { ObjectHandle::from_retained_ptr(out_buffer) }.map(MeshBuffer::from_handle))
212    }
213
214    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh buffer allocator counterpart.
215    pub fn new_buffer_from_zone_with_data(
216        &self,
217        zone: Option<&MeshBufferZone>,
218        data: &[u8],
219        buffer_type: MeshBufferType,
220    ) -> Result<Option<MeshBuffer>> {
221        let mut out_buffer = ptr::null_mut();
222        let mut out_error = ptr::null_mut();
223        // SAFETY: The unsafe operation is valid in this context.
224        let status = unsafe {
225            ffi::mdl_mesh_buffer_allocator_new_buffer_from_zone_data(
226                self.as_ptr(),
227                zone.map_or(ptr::null_mut(), MeshBufferZone::as_ptr),
228                data.as_ptr(),
229                data.len() as u64,
230                buffer_type.as_raw(),
231                &mut out_buffer,
232                &mut out_error,
233            )
234        };
235        crate::util::status_result(status, out_error)?;
236        // SAFETY: The unsafe operation is valid in this context.
237        Ok(unsafe { ObjectHandle::from_retained_ptr(out_buffer) }.map(MeshBuffer::from_handle))
238    }
239}
240
241#[derive(Debug, Clone)]
242/// Wraps the corresponding Model I/O mesh buffer zone counterpart.
243pub struct MeshBufferZone {
244    handle: ObjectHandle,
245}
246
247impl MeshBufferZone {
248    /// Builds this wrapper from the retained handle of the wrapped Model I/O mesh buffer zone counterpart.
249    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
250        Self { handle }
251    }
252
253    /// Returns the opaque pointer used to call the wrapped Model I/O mesh buffer zone counterpart.
254    pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
255        self.handle.as_ptr()
256    }
257
258    #[must_use]
259    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer zone counterpart.
260    pub fn capacity(&self) -> usize {
261        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
262        unsafe { ffi::mdl_mesh_buffer_zone_capacity(self.as_ptr()) as usize }
263    }
264
265    #[must_use]
266    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer zone counterpart.
267    pub fn allocator(&self) -> Option<MeshBufferAllocator> {
268        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
269        let ptr = unsafe { ffi::mdl_mesh_buffer_zone_allocator(self.as_ptr()) };
270        // SAFETY: The unsafe operation is valid in this context.
271        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferAllocator::from_handle)
272    }
273
274    #[must_use]
275    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer zone counterpart.
276    pub fn as_default(&self) -> Option<MeshBufferZoneDefault> {
277        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
278        (unsafe { ffi::mdl_mesh_buffer_zone_is_default(self.as_ptr()) != 0 })
279            .then(|| MeshBufferZoneDefault::from_handle(self.handle.clone()))
280    }
281}
282
283#[derive(Debug, Clone)]
284/// Wraps the corresponding Model I/O mesh buffer zone default counterpart.
285pub struct MeshBufferZoneDefault {
286    handle: ObjectHandle,
287}
288
289impl MeshBufferZoneDefault {
290    fn from_handle(handle: ObjectHandle) -> Self {
291        Self { handle }
292    }
293
294    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh buffer zone default counterpart.
295    pub fn new() -> Result<Self> {
296        let mut out_zone = ptr::null_mut();
297        let mut out_error = ptr::null_mut();
298        let status =
299            // SAFETY: Output pointers are initialized and managed; FFI function is called safely.
300            unsafe { ffi::mdl_mesh_buffer_zone_default_new(&mut out_zone, &mut out_error) };
301        crate::util::status_result(status, out_error)?;
302        Ok(Self::from_handle(required_handle(
303            out_zone,
304            "MDLMeshBufferZoneDefault",
305        )?))
306    }
307
308    #[must_use]
309    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer zone default counterpart.
310    pub fn capacity(&self) -> usize {
311        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
312        unsafe { ffi::mdl_mesh_buffer_zone_capacity(self.handle.as_ptr()) as usize }
313    }
314
315    #[must_use]
316    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer zone default counterpart.
317    pub fn allocator(&self) -> Option<MeshBufferAllocator> {
318        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
319        let ptr = unsafe { ffi::mdl_mesh_buffer_zone_allocator(self.handle.as_ptr()) };
320        // SAFETY: The unsafe operation is valid in this context.
321        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferAllocator::from_handle)
322    }
323
324    #[must_use]
325    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer zone default counterpart.
326    pub fn as_mesh_buffer_zone(&self) -> MeshBufferZone {
327        MeshBufferZone::from_handle(self.handle.clone())
328    }
329}
330
331#[derive(Debug, Clone)]
332/// Wraps the corresponding Model I/O mesh buffer data counterpart.
333pub struct MeshBufferData {
334    handle: ObjectHandle,
335}
336
337impl MeshBufferData {
338    fn from_handle(handle: ObjectHandle) -> Self {
339        Self { handle }
340    }
341
342    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh buffer data counterpart.
343    pub fn new(length: usize, buffer_type: MeshBufferType) -> Result<Self> {
344        let mut out_buffer = ptr::null_mut();
345        let mut out_error = ptr::null_mut();
346        // SAFETY: The unsafe operation is valid in this context.
347        let status = unsafe {
348            ffi::mdl_mesh_buffer_data_new(
349                length as u64,
350                buffer_type.as_raw(),
351                &mut out_buffer,
352                &mut out_error,
353            )
354        };
355        crate::util::status_result(status, out_error)?;
356        Ok(Self::from_handle(required_handle(
357            out_buffer,
358            "MDLMeshBufferData",
359        )?))
360    }
361
362    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer data counterpart.
363    pub fn from_bytes(data: &[u8], buffer_type: MeshBufferType) -> Result<Self> {
364        let mut out_buffer = ptr::null_mut();
365        let mut out_error = ptr::null_mut();
366        // SAFETY: The unsafe operation is valid in this context.
367        let status = unsafe {
368            ffi::mdl_mesh_buffer_data_new_with_bytes(
369                data.as_ptr(),
370                data.len() as u64,
371                buffer_type.as_raw(),
372                &mut out_buffer,
373                &mut out_error,
374            )
375        };
376        crate::util::status_result(status, out_error)?;
377        Ok(Self::from_handle(required_handle(
378            out_buffer,
379            "MDLMeshBufferData",
380        )?))
381    }
382
383    #[must_use]
384    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer data counterpart.
385    pub fn data(&self) -> Vec<u8> {
386        let info = self.as_mesh_buffer().info().ok();
387        let mut bytes = vec![0_u8; info.map_or(0, |buffer| buffer.length)];
388        if bytes.is_empty() {
389            return bytes;
390        }
391        // SAFETY: The unsafe operation is valid in this context.
392        let written = unsafe {
393            ffi::mdl_mesh_buffer_data_copy_data(
394                self.handle.as_ptr(),
395                bytes.as_mut_ptr(),
396                bytes.len() as u64,
397            )
398        } as usize;
399        bytes.truncate(written);
400        bytes
401    }
402
403    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer data counterpart.
404    pub fn map(&self) -> Result<MeshBufferMap> {
405        self.as_mesh_buffer().map()
406    }
407
408    #[must_use]
409    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer data counterpart.
410    pub fn as_mesh_buffer(&self) -> MeshBuffer {
411        MeshBuffer::from_handle(self.handle.clone())
412    }
413}
414
415#[derive(Debug, Clone)]
416/// Wraps the corresponding Model I/O mesh buffer data allocator counterpart.
417pub struct MeshBufferDataAllocator {
418    handle: ObjectHandle,
419}
420
421impl MeshBufferDataAllocator {
422    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh buffer data allocator counterpart.
423    pub fn new() -> Result<Self> {
424        let mut out_allocator = ptr::null_mut();
425        let mut out_error = ptr::null_mut();
426        let status =
427            // SAFETY: Output pointers are initialized and managed; FFI function is called safely.
428            unsafe { ffi::mdl_mesh_buffer_data_allocator_new(&mut out_allocator, &mut out_error) };
429        crate::util::status_result(status, out_error)?;
430        Ok(Self {
431            handle: required_handle(out_allocator, "MDLMeshBufferDataAllocator")?,
432        })
433    }
434
435    #[must_use]
436    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer data allocator counterpart.
437    pub fn as_mesh_buffer_allocator(&self) -> MeshBufferAllocator {
438        MeshBufferAllocator::from_handle(self.handle.clone())
439    }
440
441    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh buffer data allocator counterpart.
442    pub fn new_default_zone(&self, capacity: usize) -> Result<MeshBufferZoneDefault> {
443        self.as_mesh_buffer_allocator()
444            .new_zone(capacity)?
445            .as_default()
446            .ok_or_else(|| {
447                ModelIoError::new(
448                    ffi::status::NULL_RESULT,
449                    "MDLMeshBufferDataAllocator zone was not MDLMeshBufferZoneDefault",
450                )
451            })
452    }
453}
454
455impl MeshBuffer {
456    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer counterpart.
457    pub fn fill_data(&self, data: &[u8], offset: usize) {
458        // SAFETY: The unsafe operation is valid in this context.
459        unsafe {
460            ffi::mdl_mesh_buffer_fill_data(
461                self.as_ptr(),
462                data.as_ptr(),
463                data.len() as u64,
464                offset as u64,
465            );
466        }
467    }
468
469    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer counterpart.
470    pub fn map(&self) -> Result<MeshBufferMap> {
471        let length = self.info()?.length;
472        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
473        let ptr = unsafe { ffi::mdl_mesh_buffer_map(self.as_ptr()) };
474        Ok(MeshBufferMap::from_handle(
475            required_handle(ptr, "MDLMeshBufferMap")?,
476            length,
477        ))
478    }
479
480    #[must_use]
481    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer counterpart.
482    pub fn allocator(&self) -> Option<MeshBufferAllocator> {
483        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
484        let ptr = unsafe { ffi::mdl_mesh_buffer_allocator(self.as_ptr()) };
485        // SAFETY: The unsafe operation is valid in this context.
486        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferAllocator::from_handle)
487    }
488
489    #[must_use]
490    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer counterpart.
491    pub fn zone(&self) -> Option<MeshBufferZone> {
492        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
493        let ptr = unsafe { ffi::mdl_mesh_buffer_zone(self.as_ptr()) };
494        // SAFETY: The unsafe operation is valid in this context.
495        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferZone::from_handle)
496    }
497
498    #[must_use]
499    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer counterpart.
500    pub fn as_data_buffer(&self) -> Option<MeshBufferData> {
501        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
502        if unsafe { ffi::mdl_mesh_buffer_is_data(self.as_ptr()) == 0 } {
503            return None;
504        }
505        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
506        let retained = unsafe { ffi::mdl_object_retain(self.as_ptr()) };
507        // SAFETY: The unsafe operation is valid in this context.
508        unsafe { ObjectHandle::from_retained_ptr(retained) }.map(MeshBufferData::from_handle)
509    }
510}