Skip to main content

audionimbus/
serialized_object.rs

1use crate::context::Context;
2use crate::error::{to_option_error, SteamAudioError};
3
4#[cfg(doc)]
5use crate::geometry::Scene;
6#[cfg(doc)]
7use crate::probe::ProbeBatch;
8
9/// A serialized representation of an API object, like a [`Scene`] or [`ProbeBatch`].
10///
11/// Create an empty serialized object if you want to serialize an existing object to a byte array, or create a serialized object that wraps an existing byte array if you want to deserialize it.
12#[derive(Debug)]
13pub struct SerializedObject(pub(crate) audionimbus_sys::IPLSerializedObject);
14
15impl SerializedObject {
16    /// Creates a new empty serialized object for serialization purposes.
17    ///
18    /// # Errors
19    ///
20    /// Returns an error if the underlying Steam Audio library fails to create the serialized object.
21    ///
22    /// # Examples
23    ///
24    /// ```
25    /// # use audionimbus::{Context, SerializedObject, SteamAudioError};
26    /// let context = Context::default();
27    /// let serialized_object = SerializedObject::try_new(&context)?;
28    /// # Ok::<(), audionimbus::SteamAudioError>(())
29    /// ```
30    pub fn try_new(context: &Context) -> Result<Self, SteamAudioError> {
31        let serialized_object_settings = audionimbus_sys::IPLSerializedObjectSettings {
32            data: std::ptr::null_mut(),
33            size: 0,
34        };
35
36        Self::try_with_settings(context, serialized_object_settings)
37    }
38
39    /// Creates a serialized object that wraps an existing byte buffer for deserialization.
40    ///
41    /// # Errors
42    ///
43    /// Returns an error if the underlying Steam Audio library fails to create the serialized
44    /// object or if the buffer contains invalid data.
45    ///
46    /// # Examples
47    ///
48    /// ```
49    /// # use audionimbus::{Context, SerializedObject, SteamAudioError};
50    /// let context = Context::default();
51    /// let mut buffer = vec![0u8; 1024]; // Load your serialized data here.
52    /// let serialized_object = SerializedObject::try_with_buffer(&context, &mut buffer)?;
53    /// # Ok::<(), audionimbus::SteamAudioError>(())
54    /// ```
55    pub fn try_with_buffer(
56        context: &Context,
57        buffer: &mut Vec<u8>,
58    ) -> Result<Self, SteamAudioError> {
59        let serialized_object_settings = audionimbus_sys::IPLSerializedObjectSettings {
60            data: buffer.as_mut_ptr().cast::<audionimbus_sys::IPLbyte>(),
61            size: buffer.len(),
62        };
63
64        Self::try_with_settings(context, serialized_object_settings)
65    }
66
67    /// Creates a serialized object with the given settings.
68    ///
69    /// # Errors
70    ///
71    /// Returns an error if the underlying Steam Audio library fails to create the object.
72    fn try_with_settings(
73        context: &Context,
74        mut serialized_object_settings: audionimbus_sys::IPLSerializedObjectSettings,
75    ) -> Result<Self, SteamAudioError> {
76        let mut serialized_object = Self(std::ptr::null_mut());
77
78        let status = unsafe {
79            audionimbus_sys::iplSerializedObjectCreate(
80                context.raw_ptr(),
81                &raw mut serialized_object_settings,
82                serialized_object.raw_ptr_mut(),
83            )
84        };
85
86        if let Some(error) = to_option_error(status) {
87            return Err(error);
88        }
89
90        Ok(serialized_object)
91    }
92
93    /// Returns the raw FFI pointer to the underlying object.
94    ///
95    /// This is intended for internal use and advanced scenarios.
96    pub const fn raw_ptr(&self) -> audionimbus_sys::IPLSerializedObject {
97        self.0
98    }
99
100    /// Returns a mutable reference to the raw FFI pointer.
101    ///
102    /// This is intended for internal use and advanced scenarios.
103    pub const fn raw_ptr_mut(&mut self) -> &mut audionimbus_sys::IPLSerializedObject {
104        &mut self.0
105    }
106
107    /// Extracts the serialized data as a byte vector.
108    ///
109    /// This method retrieves the underlying serialized data and copies it into a new
110    /// `Vec<u8>`. Use this to extract serialized data that can be saved to a file or
111    /// transmitted over the network.
112    ///
113    /// # Returns
114    ///
115    /// A `Vec<u8>` containing a copy of the serialized data.
116    ///
117    /// # Examples
118    ///
119    /// ```
120    /// # use audionimbus::{Context, SerializedObject, Scene};
121    /// # let context = Context::default();
122    /// # let serialized_object = SerializedObject::try_new(&context)?;
123    /// // After serializing some object into serialized_object...
124    /// let bytes = serialized_object.to_vec();
125    /// # Ok::<(), audionimbus::SteamAudioError>(())
126    /// ```
127    pub fn to_vec(&self) -> Vec<u8> {
128        let raw_ptr = self.raw_ptr();
129
130        let data_ptr = unsafe { audionimbus_sys::iplSerializedObjectGetData(raw_ptr) };
131
132        let size = unsafe { audionimbus_sys::iplSerializedObjectGetSize(raw_ptr) } as usize;
133
134        if data_ptr.is_null() || size == 0 {
135            return Vec::new();
136        }
137
138        let data_slice = unsafe { std::slice::from_raw_parts(data_ptr, size) };
139
140        data_slice.to_vec()
141    }
142}
143
144impl Drop for SerializedObject {
145    fn drop(&mut self) {
146        unsafe { audionimbus_sys::iplSerializedObjectRelease(&raw mut self.0) }
147    }
148}
149
150unsafe impl Send for SerializedObject {}
151unsafe impl Sync for SerializedObject {}
152
153impl Clone for SerializedObject {
154    /// Retains an additional reference to the serialized object.
155    ///
156    /// The returned [`SerializedObject`] shares the same underlying Steam Audio object.
157    fn clone(&self) -> Self {
158        // SAFETY: The serialized object will not be destroyed until all references are released.
159        Self(unsafe { audionimbus_sys::iplSerializedObjectRetain(self.0) })
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166
167    #[test]
168    fn test_try_new() {
169        let context = Context::default();
170        let serialized_object = SerializedObject::try_new(&context);
171        assert!(serialized_object.is_ok());
172    }
173
174    #[test]
175    fn test_try_with_buffer() {
176        let context = Context::default();
177        let mut buffer = vec![0u8; 1024];
178        let serialized_object = SerializedObject::try_with_buffer(&context, &mut buffer);
179        assert!(serialized_object.is_ok());
180    }
181
182    #[test]
183    fn test_clone() {
184        let context = Context::default();
185        let serialized_object = SerializedObject::try_new(&context).unwrap();
186        let clone = serialized_object.clone();
187        assert_eq!(serialized_object.raw_ptr(), clone.raw_ptr());
188        drop(serialized_object);
189        assert!(!clone.raw_ptr().is_null());
190    }
191}