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}