gemini_genai_rs/buffer/convert.rs
1//! Zero-copy audio sample format conversion.
2//!
3//! Provides utilities for converting between i16 PCM sample slices and raw byte
4//! slices using [`bytemuck`] (zero-copy reinterpret casts), and for wrapping
5//! owned byte vectors as shared [`Bytes`] handles for zero-copy fan-out.
6
7use bytes::Bytes;
8
9/// Convert a slice of i16 PCM samples to raw bytes (zero-copy via bytemuck).
10pub fn i16_to_bytes(samples: &[i16]) -> &[u8] {
11 bytemuck::cast_slice(samples)
12}
13
14/// Convert raw bytes to i16 PCM samples (zero-copy via bytemuck).
15///
16/// Returns `None` if the byte slice length is not a multiple of 2.
17pub fn bytes_to_i16(data: &[u8]) -> Option<&[i16]> {
18 bytemuck::try_cast_slice(data).ok()
19}
20
21/// Wrap raw bytes as a shared `Bytes` handle for zero-copy fan-out.
22///
23/// `Bytes::clone()` is O(1) — it bumps an internal `Arc` refcount instead of
24/// copying the data. Use this when the same audio chunk must be broadcast to
25/// multiple subscribers.
26pub fn into_shared(data: Vec<u8>) -> Bytes {
27 Bytes::from(data)
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33
34 #[test]
35 fn test_i16_to_bytes_round_trip() {
36 let samples: Vec<i16> = vec![0, 1, -1, i16::MAX, i16::MIN, 12345];
37 let raw = i16_to_bytes(&samples);
38 assert_eq!(raw.len(), samples.len() * 2);
39
40 let back = bytes_to_i16(raw).expect("round-trip should succeed");
41 assert_eq!(back, &samples[..]);
42 }
43
44 #[test]
45 fn test_bytes_to_i16_invalid_length() {
46 // Odd-length byte slice cannot be reinterpreted as &[i16]
47 let odd = vec![1u8, 2, 3];
48 assert!(bytes_to_i16(&odd).is_none());
49 }
50
51 #[test]
52 fn test_shared_bytes_clone_is_cheap() {
53 let original = vec![42u8; 4096];
54 let ptr = original.as_ptr();
55 let shared = into_shared(original);
56
57 // Clone should share the same backing allocation
58 let cloned = shared.clone();
59 assert_eq!(shared.as_ptr(), cloned.as_ptr());
60 // The data pointer may differ from the original Vec (Bytes may reallocate
61 // during From<Vec<u8>>), but the two Bytes handles must share the same
62 // underlying memory.
63 let _ = ptr; // original vec was consumed
64 assert_eq!(&shared[..], &cloned[..]);
65 assert_eq!(shared.len(), 4096);
66 }
67}