1use std::collections::VecDeque;
11use std::task::{Poll, ready};
12
13use bytes::Bytes;
14
15use crate::{Error, MAX_FRAME_SIZE, Result};
16
17use super::{Frame, FrameConsumer, FrameProducer};
18
19const MAX_GROUP_CACHE: u64 = 32 * 1024 * 1024; const MAX_GROUP_FRAMES: usize = 1024;
26
27#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub struct Group {
33 pub sequence: u64,
36}
37
38impl Group {
39 pub fn produce(self) -> GroupProducer {
41 GroupProducer::new(self)
42 }
43}
44
45impl From<usize> for Group {
46 fn from(sequence: usize) -> Self {
47 Self {
48 sequence: sequence as u64,
49 }
50 }
51}
52
53impl From<u64> for Group {
54 fn from(sequence: u64) -> Self {
55 Self { sequence }
56 }
57}
58
59impl From<u32> for Group {
60 fn from(sequence: u32) -> Self {
61 Self {
62 sequence: sequence as u64,
63 }
64 }
65}
66
67impl From<u16> for Group {
68 fn from(sequence: u16) -> Self {
69 Self {
70 sequence: sequence as u64,
71 }
72 }
73}
74
75#[derive(Default)]
76struct GroupState {
77 frames: VecDeque<FrameProducer>,
80
81 offset: usize,
83
84 cache: u64,
86
87 fin: bool,
89
90 abort: Option<Error>,
92}
93
94impl GroupState {
95 fn poll_get_frame(&self, index: usize) -> Poll<Result<Option<FrameConsumer>>> {
96 if index < self.offset {
97 Poll::Ready(Err(Error::CacheFull))
98 } else if let Some(frame) = self.frames.get(index - self.offset) {
99 Poll::Ready(Ok(Some(frame.consume())))
100 } else if self.fin {
101 Poll::Ready(Ok(None))
102 } else if let Some(err) = &self.abort {
103 Poll::Ready(Err(err.clone()))
104 } else {
105 Poll::Pending
106 }
107 }
108
109 fn poll_frame_read_all(&self, index: usize, waiter: &kio::Waiter) -> Poll<Result<Option<Bytes>>> {
116 if index < self.offset {
117 return Poll::Ready(Err(Error::CacheFull));
118 }
119 match self.frames.get(index - self.offset) {
120 Some(frame) => Poll::Ready(Ok(Some(ready!(frame.poll_read_all(waiter))?))),
121 None if self.fin => Poll::Ready(Ok(None)),
122 None => match &self.abort {
123 Some(err) => Poll::Ready(Err(err.clone())),
124 None => Poll::Pending,
125 },
126 }
127 }
128
129 fn poll_finished(&self) -> Poll<Result<u64>> {
130 if self.fin {
131 Poll::Ready(Ok((self.offset + self.frames.len()) as u64))
132 } else if let Some(err) = &self.abort {
133 Poll::Ready(Err(err.clone()))
134 } else {
135 Poll::Pending
136 }
137 }
138
139 fn evict(&mut self) {
141 while self.cache > MAX_GROUP_CACHE || self.frames.len() > MAX_GROUP_FRAMES {
142 let Some(frame) = self.frames.pop_front() else {
143 break;
144 };
145 self.cache -= frame.size;
146 self.offset += 1;
147 }
148 }
149}
150
151fn modify(state: &kio::Producer<GroupState>) -> Result<kio::Mut<'_, GroupState>> {
152 state.write().map_err(|r| r.abort.clone().unwrap_or(Error::Dropped))
153}
154
155pub struct GroupProducer {
161 state: kio::Producer<GroupState>,
163
164 info: Group,
166}
167
168impl std::ops::Deref for GroupProducer {
169 type Target = Group;
170
171 fn deref(&self) -> &Self::Target {
172 &self.info
173 }
174}
175
176impl GroupProducer {
177 pub fn new(info: Group) -> Self {
179 Self {
180 info,
181 state: kio::Producer::default(),
182 }
183 }
184
185 pub fn write_frame<B: Into<Bytes>>(&mut self, frame: B) -> Result<()> {
190 let data = frame.into();
191 let frame = Frame {
192 size: data.len() as u64,
193 };
194 let mut frame = self.create_frame(frame)?;
195 frame.write(data)?;
196 frame.finish()?;
197 Ok(())
198 }
199
200 pub fn create_frame(&mut self, info: Frame) -> Result<FrameProducer> {
202 if info.size > MAX_FRAME_SIZE {
205 return Err(Error::FrameTooLarge);
206 }
207 let frame = info.produce();
208 self.append_frame(frame.clone())?;
209 Ok(frame)
210 }
211
212 pub fn append_frame(&mut self, frame: FrameProducer) -> Result<()> {
214 if frame.size > MAX_FRAME_SIZE {
217 return Err(Error::FrameTooLarge);
218 }
219 let mut state = modify(&self.state)?;
220 if state.fin {
221 return Err(Error::Closed);
222 }
223 state.cache += frame.size;
224 state.frames.push_back(frame);
225 state.evict();
226 Ok(())
227 }
228
229 pub fn frame_count(&self) -> usize {
231 let state = self.state.read();
232 state.offset + state.frames.len()
233 }
234
235 pub fn finish(&mut self) -> Result<()> {
237 let mut state = modify(&self.state)?;
238 state.fin = true;
239 Ok(())
240 }
241
242 pub fn abort(&mut self, err: Error) -> Result<()> {
250 let mut guard = modify(&self.state)?;
251 guard.abort = Some(err);
252 guard.frames.clear();
253 guard.cache = 0;
254 guard.close();
255 Ok(())
256 }
257
258 pub fn consume(&self) -> GroupConsumer {
260 GroupConsumer {
261 info: self.info.clone(),
262 state: self.state.consume(),
263 index: 0,
264 }
265 }
266
267 pub async fn closed(&self) -> Error {
269 self.state.closed().await;
270 self.state.read().abort.clone().unwrap_or(Error::Dropped)
271 }
272
273 pub async fn unused(&self) -> Result<()> {
275 self.state
276 .unused()
277 .await
278 .map_err(|r| r.abort.clone().unwrap_or(Error::Dropped))
279 }
280}
281
282impl Clone for GroupProducer {
283 fn clone(&self) -> Self {
284 Self {
285 info: self.info.clone(),
286 state: self.state.clone(),
287 }
288 }
289}
290
291impl Drop for GroupProducer {
292 fn drop(&mut self) {
293 if !self.state.is_last() {
297 return;
298 }
299 if let Ok(mut state) = modify(&self.state)
300 && !state.fin
301 {
302 state.frames.clear();
303 state.cache = 0;
304 }
305 }
306}
307
308impl From<Group> for GroupProducer {
309 fn from(info: Group) -> Self {
310 GroupProducer::new(info)
311 }
312}
313
314#[derive(Clone)]
316pub struct GroupConsumer {
317 state: kio::Consumer<GroupState>,
319
320 info: Group,
322
323 index: usize,
326}
327
328impl std::ops::Deref for GroupConsumer {
329 type Target = Group;
330
331 fn deref(&self) -> &Self::Target {
332 &self.info
333 }
334}
335
336impl GroupConsumer {
337 fn poll<F, R>(&self, waiter: &kio::Waiter, f: F) -> Poll<Result<R>>
339 where
340 F: Fn(&kio::Ref<'_, GroupState>) -> Poll<Result<R>>,
341 {
342 Poll::Ready(match ready!(self.state.poll(waiter, f)) {
343 Ok(res) => res,
344 Err(state) => Err(state.abort.clone().unwrap_or(Error::Dropped)),
346 })
347 }
348
349 pub async fn get_frame(&self, index: usize) -> Result<Option<FrameConsumer>> {
353 kio::wait(|waiter| self.poll_get_frame(waiter, index)).await
354 }
355
356 pub fn poll_get_frame(&self, waiter: &kio::Waiter, index: usize) -> Poll<Result<Option<FrameConsumer>>> {
360 self.poll(waiter, |state| state.poll_get_frame(index))
361 }
362
363 pub async fn next_frame(&mut self) -> Result<Option<FrameConsumer>> {
365 kio::wait(|waiter| self.poll_next_frame(waiter)).await
366 }
367
368 pub fn poll_next_frame(&mut self, waiter: &kio::Waiter) -> Poll<Result<Option<FrameConsumer>>> {
372 let Some(frame) = ready!(self.poll(waiter, |state| state.poll_get_frame(self.index))?) else {
373 return Poll::Ready(Ok(None));
374 };
375
376 self.index += 1;
377 Poll::Ready(Ok(Some(frame)))
378 }
379
380 pub fn poll_read_frame(&mut self, waiter: &kio::Waiter) -> Poll<Result<Option<Bytes>>> {
382 let index = self.index;
383 let Some(data) = ready!(self.poll(waiter, |state| state.poll_frame_read_all(index, waiter))?) else {
384 return Poll::Ready(Ok(None));
385 };
386
387 self.index += 1;
388 Poll::Ready(Ok(Some(data)))
389 }
390
391 pub async fn read_frame(&mut self) -> Result<Option<Bytes>> {
393 kio::wait(|waiter| self.poll_read_frame(waiter)).await
394 }
395
396 pub fn poll_read_frame_chunks(&mut self, waiter: &kio::Waiter) -> Poll<Result<Option<Vec<Bytes>>>> {
398 let index = self.index;
399 let Some(data) = ready!(self.poll(waiter, |state| state.poll_frame_read_all(index, waiter))?) else {
400 return Poll::Ready(Ok(None));
401 };
402
403 self.index += 1;
404 Poll::Ready(Ok(Some(if data.is_empty() { Vec::new() } else { vec![data] })))
407 }
408
409 pub async fn read_frame_chunks(&mut self) -> Result<Option<Vec<Bytes>>> {
411 kio::wait(|waiter| self.poll_read_frame_chunks(waiter)).await
412 }
413
414 pub fn poll_finished(&mut self, waiter: &kio::Waiter) -> Poll<Result<u64>> {
416 self.poll(waiter, |state| state.poll_finished())
417 }
418
419 pub async fn finished(&mut self) -> Result<u64> {
421 kio::wait(|waiter| self.poll_finished(waiter)).await
422 }
423}
424
425#[cfg(test)]
426mod test {
427 use super::*;
428 use futures::FutureExt;
429
430 #[test]
431 fn basic_frame_reading() {
432 let mut producer = Group { sequence: 0 }.produce();
433 producer.write_frame(Bytes::from_static(b"frame0")).unwrap();
434 producer.write_frame(Bytes::from_static(b"frame1")).unwrap();
435 producer.finish().unwrap();
436
437 let mut consumer = producer.consume();
438 let f0 = consumer.next_frame().now_or_never().unwrap().unwrap().unwrap();
439 assert_eq!(f0.size, 6);
440 let f1 = consumer.next_frame().now_or_never().unwrap().unwrap().unwrap();
441 assert_eq!(f1.size, 6);
442 let end = consumer.next_frame().now_or_never().unwrap().unwrap();
443 assert!(end.is_none());
444 }
445
446 #[test]
447 fn read_frame_all_at_once() {
448 let mut producer = Group { sequence: 0 }.produce();
449 producer.write_frame(Bytes::from_static(b"hello")).unwrap();
450 producer.finish().unwrap();
451
452 let mut consumer = producer.consume();
453 let data = consumer.read_frame().now_or_never().unwrap().unwrap().unwrap();
454 assert_eq!(data, Bytes::from_static(b"hello"));
455 }
456
457 #[test]
458 fn read_frame_chunks() {
459 let mut producer = Group { sequence: 0 }.produce();
460 let mut frame = producer.create_frame(Frame { size: 10 }).unwrap();
461 frame.write(Bytes::from_static(b"hello")).unwrap();
462 frame.write(Bytes::from_static(b"world")).unwrap();
463 frame.finish().unwrap();
464 producer.finish().unwrap();
465
466 let mut consumer = producer.consume();
469 let chunks = consumer.read_frame_chunks().now_or_never().unwrap().unwrap().unwrap();
470 assert_eq!(chunks.len(), 1);
471 assert_eq!(chunks[0], Bytes::from_static(b"helloworld"));
472 }
473
474 #[test]
475 fn append_rejects_oversized_frame() {
476 let mut producer = Group { sequence: 0 }.produce();
477 let err = producer.create_frame(Frame {
478 size: MAX_FRAME_SIZE + 1,
479 });
480 assert!(
481 matches!(err, Err(Error::FrameTooLarge)),
482 "a frame over the limit is rejected"
483 );
484 assert!(producer.create_frame(Frame { size: MAX_FRAME_SIZE }).is_ok());
486 }
487
488 #[test]
489 fn get_frame_by_index() {
490 let mut producer = Group { sequence: 0 }.produce();
491 producer.write_frame(Bytes::from_static(b"a")).unwrap();
492 producer.write_frame(Bytes::from_static(b"bb")).unwrap();
493 producer.finish().unwrap();
494
495 let consumer = producer.consume();
496 let f0 = consumer.get_frame(0).now_or_never().unwrap().unwrap().unwrap();
497 assert_eq!(f0.size, 1);
498 let f1 = consumer.get_frame(1).now_or_never().unwrap().unwrap().unwrap();
499 assert_eq!(f1.size, 2);
500 let f2 = consumer.get_frame(2).now_or_never().unwrap().unwrap();
501 assert!(f2.is_none());
502 }
503
504 #[test]
505 fn group_finish_returns_none() {
506 let mut producer = Group { sequence: 0 }.produce();
507 producer.finish().unwrap();
508
509 let mut consumer = producer.consume();
510 let end = consumer.next_frame().now_or_never().unwrap().unwrap();
511 assert!(end.is_none());
512 }
513
514 #[test]
515 fn abort_propagates() {
516 let mut producer = Group { sequence: 0 }.produce();
517 let mut consumer = producer.consume();
518 producer.abort(crate::Error::Cancel).unwrap();
519
520 let result = consumer.next_frame().now_or_never().unwrap();
521 assert!(matches!(result, Err(crate::Error::Cancel)));
522 }
523
524 #[test]
525 fn abort_clears_cached_frames() {
526 let mut producer = Group { sequence: 0 }.produce();
527 producer.write_frame(Bytes::from_static(b"data")).unwrap();
528
529 let _consumer = producer.consume();
531 assert_eq!(producer.state.read().frames.len(), 1);
532
533 producer.abort(crate::Error::Cancel).unwrap();
534
535 let state = producer.state.read();
536 assert!(state.frames.is_empty(), "cached frames should be dropped on abort");
537 assert_eq!(state.cache, 0);
538 }
539
540 #[test]
541 fn drop_unfinished_clears_cached_frames() {
542 let producer = Group { sequence: 0 }.produce();
543 let mut writer = producer.clone();
544 writer.write_frame(Bytes::from_static(b"data")).unwrap();
545
546 let mut consumer = producer.consume();
548 assert_eq!(producer.state.read().frames.len(), 1);
549
550 drop(writer);
552 drop(producer);
553
554 let result = consumer.next_frame().now_or_never().unwrap();
555 assert!(matches!(result, Err(crate::Error::Dropped)));
556 }
557
558 #[test]
559 fn drop_finished_keeps_cached_frames() {
560 let mut producer = Group { sequence: 0 }.produce();
561 producer.write_frame(Bytes::from_static(b"data")).unwrap();
562 producer.finish().unwrap();
563
564 let mut consumer = producer.consume();
565 drop(producer);
566
567 let frame = consumer.read_frame().now_or_never().unwrap().unwrap().unwrap();
569 assert_eq!(frame, Bytes::from_static(b"data"));
570 }
571
572 #[tokio::test]
573 async fn pending_then_ready() {
574 let mut producer = Group { sequence: 0 }.produce();
575 let mut consumer = producer.consume();
576
577 assert!(consumer.next_frame().now_or_never().is_none());
579
580 producer.write_frame(Bytes::from_static(b"data")).unwrap();
581 producer.finish().unwrap();
582
583 let frame = consumer.next_frame().now_or_never().unwrap().unwrap().unwrap();
584 assert_eq!(frame.size, 4);
585 }
586
587 #[test]
588 fn eviction_drops_old_frames() {
589 let mut producer = Group { sequence: 0 }.produce();
590
591 let big = Bytes::from(vec![0u8; MAX_GROUP_CACHE as usize]);
593 producer.write_frame(big.clone()).unwrap();
594 producer.write_frame(big).unwrap();
595
596 let consumer = producer.consume();
598 let result = consumer.get_frame(0).now_or_never().unwrap();
599 assert!(matches!(result, Err(crate::Error::CacheFull)));
600
601 let f1 = consumer.get_frame(1).now_or_never().unwrap().unwrap().unwrap();
603 assert_eq!(f1.size, MAX_GROUP_CACHE);
604 }
605
606 #[test]
607 fn no_eviction_under_limit() {
608 let mut producer = Group { sequence: 0 }.produce();
609 producer.write_frame(Bytes::from_static(b"small")).unwrap();
610 producer.write_frame(Bytes::from_static(b"frames")).unwrap();
611 producer.finish().unwrap();
612
613 let consumer = producer.consume();
614 let f0 = consumer.get_frame(0).now_or_never().unwrap().unwrap().unwrap();
615 assert_eq!(f0.size, 5);
616 let f1 = consumer.get_frame(1).now_or_never().unwrap().unwrap().unwrap();
617 assert_eq!(f1.size, 6);
618 }
619
620 #[test]
621 fn eviction_by_frame_count() {
622 let mut producer = Group { sequence: 0 }.produce();
623
624 for _ in 0..=MAX_GROUP_FRAMES {
626 producer.write_frame(Bytes::from_static(b"x")).unwrap();
627 }
628
629 let consumer = producer.consume();
631 let result = consumer.get_frame(0).now_or_never().unwrap();
632 assert!(matches!(result, Err(crate::Error::CacheFull)));
633
634 let f = consumer
636 .get_frame(MAX_GROUP_FRAMES)
637 .now_or_never()
638 .unwrap()
639 .unwrap()
640 .unwrap();
641 assert_eq!(f.size, 1);
642 }
643
644 #[test]
645 fn next_frame_returns_cache_full_on_tombstone() {
646 let mut producer = Group { sequence: 0 }.produce();
647
648 let big = Bytes::from(vec![0u8; MAX_GROUP_CACHE as usize]);
649 producer.write_frame(big.clone()).unwrap();
650 producer.write_frame(big).unwrap();
651
652 let mut consumer = producer.consume();
653 let result = consumer.next_frame().now_or_never().unwrap();
655 assert!(matches!(result, Err(crate::Error::CacheFull)));
656 }
657
658 #[test]
659 fn clone_consumer_independent() {
660 let mut producer = Group { sequence: 0 }.produce();
661 producer.write_frame(Bytes::from_static(b"a")).unwrap();
662
663 let mut c1 = producer.consume();
664 let _ = c1.next_frame().now_or_never().unwrap().unwrap().unwrap();
666
667 let mut c2 = c1.clone();
669
670 producer.write_frame(Bytes::from_static(b"b")).unwrap();
671 producer.finish().unwrap();
672
673 let f = c2.next_frame().now_or_never().unwrap().unwrap().unwrap();
675 assert_eq!(f.size, 1); let end = c2.next_frame().now_or_never().unwrap().unwrap();
678 assert!(end.is_none());
679 }
680}