1use std::sync::atomic::{AtomicU64, Ordering};
8use std::sync::Arc;
9
10use rtrb::{Consumer, Producer, RingBuffer};
11
12pub fn raw_ring(capacity_samples: usize) -> (RawProducer, RawConsumer) {
17 let cap = capacity_samples.max(1);
18 let (prod, cons) = RingBuffer::<f32>::new(cap);
19 let overflow = Arc::new(AtomicU64::new(0));
20 (
21 RawProducer {
22 inner: prod,
23 overflow: overflow.clone(),
24 },
25 RawConsumer {
26 inner: cons,
27 overflow,
28 },
29 )
30}
31
32pub struct RawProducer {
34 inner: Producer<f32>,
35 overflow: Arc<AtomicU64>,
36}
37
38impl RawProducer {
39 pub fn push_slice(&mut self, samples: &[f32]) -> usize {
44 if samples.is_empty() {
45 return 0;
46 }
47 let free = self.inner.slots();
48 let writable = free.min(samples.len());
49
50 if writable > 0 {
51 if let Ok(mut chunk) = self.inner.write_chunk_uninit(writable) {
53 let (a, b) = chunk.as_mut_slices();
54 let (head, tail) = samples.split_at(a.len().min(samples.len()));
55 for (dst, &src) in a.iter_mut().zip(head.iter()) {
56 dst.write(src);
57 }
58 let tail = &tail[..b.len().min(tail.len())];
59 for (dst, &src) in b.iter_mut().zip(tail.iter()) {
60 dst.write(src);
61 }
62 unsafe { chunk.commit_all() };
64 }
65 }
66
67 let dropped = samples.len() - writable;
68 if dropped > 0 {
69 self.overflow.fetch_add(dropped as u64, Ordering::Relaxed);
70 }
71 writable
72 }
73
74 pub fn overflow_count(&self) -> u64 {
76 self.overflow.load(Ordering::Relaxed)
77 }
78}
79
80pub struct RawConsumer {
82 inner: Consumer<f32>,
83 overflow: Arc<AtomicU64>,
84}
85
86impl RawConsumer {
87 pub fn pop_slice(&mut self, dst: &mut [f32]) -> usize {
89 let avail = self.inner.slots();
90 let n = avail.min(dst.len());
91 if n == 0 {
92 return 0;
93 }
94 if let Ok(chunk) = self.inner.read_chunk(n) {
95 let (a, b) = chunk.as_slices();
96 let (alen, blen) = (a.len(), b.len());
97 dst[..alen].copy_from_slice(a);
98 dst[alen..alen + blen].copy_from_slice(b);
99 chunk.commit_all();
100 alen + blen
101 } else {
102 0
103 }
104 }
105
106 pub fn pop(&mut self) -> Option<f32> {
108 self.inner.pop().ok()
109 }
110
111 pub fn available(&self) -> usize {
113 self.inner.slots()
114 }
115
116 pub fn overflow_count(&self) -> u64 {
118 self.overflow.load(Ordering::Relaxed)
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn push_and_pop_roundtrip() {
128 let (mut p, mut c) = raw_ring(16);
129 let n = p.push_slice(&[1.0, 2.0, 3.0, 4.0]);
130 assert_eq!(n, 4);
131 let mut out = [0.0f32; 4];
132 let got = c.pop_slice(&mut out);
133 assert_eq!(got, 4);
134 assert_eq!(out, [1.0, 2.0, 3.0, 4.0]);
135 assert_eq!(p.overflow_count(), 0);
136 }
137
138 #[test]
139 fn overflow_counts_dropped_and_never_blocks() {
140 let (mut p, mut c) = raw_ring(4);
141 let written = p.push_slice(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
143 assert_eq!(written, 4);
144 assert_eq!(p.overflow_count(), 2);
145 assert_eq!(c.overflow_count(), 2);
146
147 let mut out = [0.0f32; 8];
148 let got = c.pop_slice(&mut out);
149 assert_eq!(got, 4);
150 assert_eq!(&out[..4], &[1.0, 2.0, 3.0, 4.0]);
151 }
152
153 #[test]
154 fn wraps_around() {
155 let (mut p, mut c) = raw_ring(4);
156 p.push_slice(&[1.0, 2.0, 3.0]);
157 let mut out = [0.0f32; 2];
158 c.pop_slice(&mut out); assert_eq!(out, [1.0, 2.0]);
160 let w = p.push_slice(&[4.0, 5.0, 6.0]);
162 assert_eq!(w, 3);
163 let mut out2 = [0.0f32; 4];
164 let got = c.pop_slice(&mut out2);
165 assert_eq!(got, 4);
166 assert_eq!(out2, [3.0, 4.0, 5.0, 6.0]);
167 }
168
169 #[test]
171 fn push_empty_is_noop() {
172 let (mut p, _c) = raw_ring(4);
173 assert_eq!(p.push_slice(&[]), 0);
174 assert_eq!(p.overflow_count(), 0);
175 }
176
177 #[test]
180 fn full_ring_drops_entire_push() {
181 let (mut p, _c) = raw_ring(4);
182 assert_eq!(p.push_slice(&[1.0, 2.0, 3.0, 4.0]), 4); let w = p.push_slice(&[5.0; 5]);
185 assert_eq!(w, 0, "満杯なら 1 つも書けない");
186 assert_eq!(
187 p.overflow_count(),
188 5,
189 "全 5 サンプルが overflow に計上される"
190 );
191 }
192
193 #[test]
196 fn pop_slice_respects_available_and_dst_len() {
197 let (mut p, mut c) = raw_ring(8);
198 p.push_slice(&[1.0, 2.0, 3.0]);
199 assert_eq!(c.available(), 3);
200 let mut big = [0.0f32; 16];
202 assert_eq!(c.pop_slice(&mut big), 3);
203 assert_eq!(&big[..3], &[1.0, 2.0, 3.0]);
204 assert_eq!(c.available(), 0);
206 assert_eq!(c.pop_slice(&mut big), 0);
207 }
208
209 #[test]
212 fn overflow_counter_exceeds_u32_max() {
213 let (mut p, _c) = raw_ring(1);
214 assert_eq!(p.push_slice(&[0.0]), 1);
216 let big = vec![0.0f32; 1000];
218 let over_u32 = u64::from(u32::MAX) + 2_000;
219 let mut total_dropped = 0u64;
220 while total_dropped < over_u32 {
221 let w = p.push_slice(&big);
222 assert_eq!(w, 0, "満杯なので 1 つも書けない");
223 total_dropped += big.len() as u64;
224 }
225 assert!(
226 p.overflow_count() > u64::from(u32::MAX),
227 "overflow は u32::MAX を超えて積み上がる: {}",
228 p.overflow_count()
229 );
230 }
231
232 #[test]
234 fn single_pop_is_fifo_then_none() {
235 let (mut p, mut c) = raw_ring(4);
236 p.push_slice(&[10.0, 20.0]);
237 assert_eq!(c.pop(), Some(10.0));
238 assert_eq!(c.pop(), Some(20.0));
239 assert_eq!(c.pop(), None);
240 }
241
242 #[test]
244 fn zero_capacity_is_clamped_to_one() {
245 let (mut p, mut c) = raw_ring(0);
246 assert_eq!(
247 p.push_slice(&[7.0, 8.0]),
248 1,
249 "容量 1 に丸められ 1 サンプルだけ入る"
250 );
251 assert_eq!(p.overflow_count(), 1);
252 assert_eq!(c.pop(), Some(7.0));
253 }
254
255 #[test]
257 fn overflow_count_is_shared_between_ends() {
258 let (mut p, c) = raw_ring(2);
259 p.push_slice(&[1.0, 2.0, 3.0, 4.0]); assert_eq!(p.overflow_count(), 2);
261 assert_eq!(
262 c.overflow_count(),
263 2,
264 "consumer 側も同じ overflow を観測する"
265 );
266 }
267}