Skip to main content

mtl_foundation/
data.rs

1//! Data type for Foundation.
2//!
3//! Corresponds to `Foundation/NSData.hpp`.
4//!
5//! # C++ Equivalent
6//!
7//! ```cpp
8//! namespace NS {
9//! class Data : public Copying<Data> {
10//! public:
11//!     void*    mutableBytes() const;
12//!     UInteger length() const;
13//! };
14//! }
15//! ```
16
17use std::ffi::c_void;
18use std::ptr::NonNull;
19
20use mtl_sys::{msg_send_0, sel};
21
22use crate::object::{Copying, Referencing};
23use crate::types::UInteger;
24
25/// An Objective-C data object.
26///
27/// C++ equivalent: `NS::Data`
28#[repr(transparent)]
29#[derive(Clone)]
30pub struct Data(NonNull<c_void>);
31
32impl Data {
33    /// Get a mutable pointer to the data's bytes.
34    ///
35    /// C++ equivalent: `void* mutableBytes() const`
36    #[inline]
37    pub fn mutable_bytes(&self) -> *mut c_void {
38        unsafe { msg_send_0(self.as_ptr(), sel!(mutableBytes)) }
39    }
40
41    /// Get the length of the data in bytes.
42    ///
43    /// C++ equivalent: `UInteger length() const`
44    #[inline]
45    pub fn length(&self) -> UInteger {
46        unsafe { msg_send_0(self.as_ptr(), sel!(length)) }
47    }
48
49    /// Create a Data from a raw pointer.
50    ///
51    /// # Safety
52    ///
53    /// The pointer must be a valid Objective-C NSData object.
54    #[inline]
55    pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
56        NonNull::new(ptr).map(Self)
57    }
58}
59
60impl Referencing for Data {
61    #[inline]
62    fn as_ptr(&self) -> *const c_void {
63        self.0.as_ptr()
64    }
65}
66
67impl Copying for Data {
68    #[inline]
69    fn copy(&self) -> Option<Self> {
70        unsafe {
71            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
72            Self::from_ptr(ptr)
73        }
74    }
75}
76
77// SAFETY: NSData is thread-safe for reference counting
78unsafe impl Send for Data {}
79unsafe impl Sync for Data {}
80
81impl std::fmt::Debug for Data {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        f.debug_struct("Data")
84            .field("ptr", &self.0)
85            .field("length", &self.length())
86            .finish()
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_data_size() {
96        // Data should be pointer-sized
97        assert_eq!(
98            std::mem::size_of::<Data>(),
99            std::mem::size_of::<*mut c_void>()
100        );
101    }
102}