Skip to main content

moq_net/model/
frame.rs

1use std::sync::Arc;
2use std::sync::atomic::{AtomicUsize, Ordering};
3use std::task::{Poll, ready};
4
5use bytes::buf::UninitSlice;
6use bytes::{BufMut, Bytes};
7
8use crate::{Error, Result};
9
10/// Maximum payload size accepted for a single frame on the wire.
11///
12/// The receive path preallocates a buffer from the declared frame size, so an
13/// untrusted peer could otherwise request a multi-gigabyte allocation with a
14/// single varint. Subscribers reject frames whose declared size exceeds this.
15///
16/// Matches the per-group cache cap (`MAX_GROUP_CACHE`), so a single frame may fill
17/// a group. 16 MiB was too tight for a high-bitrate CMAF fragment carried as one
18/// frame; 32 MiB covers that while keeping the per-frame preallocation bounded.
19///
20/// Enforced on the wire decode (above) and in
21/// [`GroupProducer::create_frame`](super::group::GroupProducer::create_frame), which rejects an
22/// oversized frame *before* `produce()` allocates its buffer. A direct `FrameProducer::new` still
23/// allocates ahead of the [`append_frame`](super::group::GroupProducer::append_frame) backstop;
24/// closing that gap means a fallible constructor, which is a breaking change left to a separate `dev` PR.
25pub(crate) const MAX_FRAME_SIZE: u64 = 32 * 1024 * 1024;
26
27/// A chunk of data with an upfront size.
28///
29/// Note that this is just the header.
30/// You use [FrameProducer] and [FrameConsumer] to deal with the frame payload, potentially chunked.
31#[derive(Clone, Debug)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33pub struct Frame {
34	/// Total payload size in bytes. Declared up front so consumers can preallocate.
35	pub size: u64,
36}
37
38impl Frame {
39	/// Create a new producer for the frame.
40	pub fn produce(self) -> FrameProducer {
41		FrameProducer::new(self)
42	}
43}
44
45impl From<usize> for Frame {
46	fn from(size: usize) -> Self {
47		Self { size: size as u64 }
48	}
49}
50
51impl From<u64> for Frame {
52	fn from(size: u64) -> Self {
53		Self { size }
54	}
55}
56
57impl From<u32> for Frame {
58	fn from(size: u32) -> Self {
59		Self { size: size as u64 }
60	}
61}
62
63impl From<u16> for Frame {
64	fn from(size: u16) -> Self {
65		Self { size: size as u64 }
66	}
67}
68
69/// Single-allocation buffer shared between a [FrameProducer] and many [FrameConsumer]s.
70///
71/// Internally an [Arc] over a thin pointer + length owning a heap allocation. The
72/// data pointer is stable for the life of any clone, so [Bytes] views taken via
73/// [Bytes::from_owner] remain valid. [Clone] is cheap (one atomic increment).
74///
75/// The producer writes through the raw pointer (sole writer); `written` provides
76/// happens-before for cross-thread reads. Implements [AsRef]<[u8]> directly so it
77/// can be passed to [Bytes::from_owner] without an extra wrapper newtype.
78#[derive(Clone)]
79struct FrameBuf(Arc<FrameBufInner>);
80
81struct FrameBufInner {
82	// Owned heap allocation of `capacity` bytes (zero-initialized).
83	data: *mut u8,
84	capacity: usize,
85	written: AtomicUsize,
86}
87
88// Safety: `data` is owned (Box-allocated, freed in Drop); the producer is the
89// sole writer; consumers only read bytes `< written`, which was set via Release
90// after the corresponding writes completed (Acquire pairs on the consumer side).
91unsafe impl Send for FrameBufInner {}
92unsafe impl Sync for FrameBufInner {}
93
94impl Drop for FrameBufInner {
95	fn drop(&mut self) {
96		// Safety: data was obtained from `Box::into_raw` of a `Box<[u8]>` of
97		// length `capacity` and is not aliased at drop (Arc refcount hit 0).
98		unsafe {
99			let slice = std::ptr::slice_from_raw_parts_mut(self.data, self.capacity);
100			drop(Box::from_raw(slice));
101		}
102	}
103}
104
105impl FrameBuf {
106	fn new(size: usize) -> Self {
107		let boxed: Box<[u8]> = vec![0u8; size].into_boxed_slice();
108		let capacity = boxed.len();
109		let data = Box::into_raw(boxed) as *mut u8;
110		Self(Arc::new(FrameBufInner {
111			data,
112			capacity,
113			written: AtomicUsize::new(0),
114		}))
115	}
116
117	fn capacity(&self) -> usize {
118		self.0.capacity
119	}
120
121	fn written(&self, ord: Ordering) -> usize {
122		self.0.written.load(ord)
123	}
124
125	/// Safety: caller must be the sole producer (FrameProducer-as-BufMut invariant).
126	unsafe fn data_ptr(&self) -> *mut u8 {
127		self.0.data
128	}
129
130	/// Safety: caller must be the sole producer; `new_written` must be `<= capacity`.
131	unsafe fn store_written(&self, new_written: usize) {
132		// Release pairs with consumers' Acquire load to publish prior writes.
133		self.0.written.store(new_written, Ordering::Release);
134	}
135}
136
137impl AsRef<[u8]> for FrameBuf {
138	fn as_ref(&self) -> &[u8] {
139		// Snapshot the initialized region (bytes the producer has written so far).
140		// Acquire pairs with the producer's Release on `written`.
141		let written = self.0.written.load(Ordering::Acquire);
142		// Safety: data..data+written is initialized (zero-init at alloc + producer
143		// writes up to `written`). The Arc keeps the allocation alive while any
144		// reference to the slice lives.
145		unsafe { std::slice::from_raw_parts(self.0.data, written) }
146	}
147}
148
149#[derive(Default, Debug)]
150struct FrameState {
151	// Whether the producer signaled a clean finish (written == capacity).
152	fin: bool,
153	// The error that aborted the frame, if any.
154	abort: Option<Error>,
155}
156
157/// Writes a frame's payload in one or more chunks.
158///
159/// The total bytes written must exactly match [Frame::size].
160/// Call [Self::finish] after writing all bytes to verify correctness.
161///
162/// Implements [BufMut] so the receive path can write directly into the
163/// pre-allocated buffer (e.g. via `tokio::io::AsyncReadExt::read_buf`).
164pub struct FrameProducer {
165	info: Frame,
166	state: kio::Producer<FrameState>,
167	buf: FrameBuf,
168}
169
170impl std::ops::Deref for FrameProducer {
171	type Target = Frame;
172
173	fn deref(&self) -> &Self::Target {
174		&self.info
175	}
176}
177
178impl FrameProducer {
179	/// Create a new frame producer for the given frame header.
180	pub fn new(info: Frame) -> Self {
181		let buf = FrameBuf::new(info.size as usize);
182		Self {
183			info,
184			state: kio::Producer::new(FrameState::default()),
185			buf,
186		}
187	}
188
189	/// Write a chunk of data to the frame.
190	///
191	/// Returns [Error::WrongSize] if the chunk would exceed the remaining bytes.
192	pub fn write<B: Into<Bytes>>(&mut self, chunk: B) -> Result<()> {
193		let chunk = chunk.into();
194		if chunk.len() > self.remaining_mut() {
195			return Err(Error::WrongSize);
196		}
197		// Surface aborts before writing.
198		self.bail_if_aborted()?;
199		self.put_slice(&chunk);
200		Ok(())
201	}
202
203	/// Verify that all bytes have been written.
204	///
205	/// Returns [Error::WrongSize] if the bytes written don't match [Frame::size].
206	pub fn finish(&mut self) -> Result<()> {
207		let written = self.buf.written(Ordering::Acquire);
208		if written != self.buf.capacity() {
209			return Err(Error::WrongSize);
210		}
211		// Mark fin (idempotent if `advance_mut` already set it on the last byte).
212		let mut state = self.modify()?;
213		state.fin = true;
214		Ok(())
215	}
216
217	/// Abort the frame with the given error.
218	pub fn abort(&mut self, err: Error) -> Result<()> {
219		let mut guard = self.modify()?;
220		guard.abort = Some(err);
221		guard.close();
222		Ok(())
223	}
224
225	/// Create a new consumer for the frame.
226	pub fn consume(&self) -> FrameConsumer {
227		FrameConsumer {
228			info: self.info.clone(),
229			state: self.state.consume(),
230			buf: self.buf.clone(),
231			read_idx: 0,
232		}
233	}
234
235	/// Poll for the frame's full payload, resolving once it's finished.
236	///
237	/// Reads from the producer side (via `kio::Producer::poll_ref`) so a polling
238	/// reader doesn't mint a transient [`FrameConsumer`] per poll: that would churn
239	/// the consumer count and wake the value waiters, spinning the poll. Always
240	/// returns the whole payload (offset 0), so it's safe to call from any number
241	/// of readers in parallel.
242	pub(crate) fn poll_read_all(&self, waiter: &kio::Waiter) -> Poll<Result<Bytes>> {
243		let res = ready!(self.state.poll_ref(waiter, |state| {
244			if state.fin {
245				Poll::Ready(Ok(()))
246			} else if let Some(err) = &state.abort {
247				Poll::Ready(Err(err.clone()))
248			} else {
249				Poll::Pending
250			}
251		}));
252
253		match res {
254			Ok(Ok(())) => {
255				// `fin` implies written == capacity (the producer fills the whole buffer).
256				let written = self.buf.written(Ordering::Acquire);
257				Poll::Ready(Ok(Bytes::from_owner(self.buf.clone()).slice(0..written)))
258			}
259			Ok(Err(err)) => Poll::Ready(Err(err)),
260			Err(state) => Poll::Ready(Err(state.abort.clone().unwrap_or(Error::Dropped))),
261		}
262	}
263
264	/// Block until there are no active consumers.
265	pub async fn unused(&self) -> Result<()> {
266		self.state
267			.unused()
268			.await
269			.map_err(|r| r.abort.clone().unwrap_or(Error::Dropped))
270	}
271
272	fn modify(&mut self) -> Result<kio::Mut<'_, FrameState>> {
273		self.state
274			.write()
275			.map_err(|r| r.abort.clone().unwrap_or(Error::Dropped))
276	}
277
278	fn bail_if_aborted(&self) -> Result<()> {
279		let state = self.state.read();
280		if let Some(err) = &state.abort {
281			return Err(err.clone());
282		}
283		Ok(())
284	}
285}
286
287// Safety: `chunk_mut` returns a slice into the producer-private region of the
288// buffer (`[written..capacity]`). Sole-writer invariant: even though
289// `FrameProducer` is `Clone`, the API exposes BufMut only via `&mut self`,
290// and existing callers never share a single producer between concurrent writers
291// (group.rs clones a handle for `abort` / `consume` only). The defensive
292// `assert!` in `advance_mut` panics loudly if that invariant is ever violated.
293unsafe impl BufMut for FrameProducer {
294	fn remaining_mut(&self) -> usize {
295		self.buf.capacity() - self.buf.written(Ordering::Acquire)
296	}
297
298	fn chunk_mut(&mut self) -> &mut UninitSlice {
299		let written = self.buf.written(Ordering::Acquire);
300		let cap = self.buf.capacity();
301		// Safety: writes to `[written..cap]` are unaliased — consumers only ever
302		// read `[..written]`, and we hold `&mut self`. The slice's lifetime is
303		// tied to `&mut self` by the function signature.
304		unsafe {
305			let ptr = self.buf.data_ptr().add(written);
306			UninitSlice::from_raw_parts_mut(ptr, cap - written)
307		}
308	}
309
310	unsafe fn advance_mut(&mut self, cnt: usize) {
311		let cap = self.buf.capacity();
312		let prev = self.buf.written(Ordering::Relaxed);
313		assert!(
314			prev + cnt <= cap,
315			"advance_mut past frame.size: prev={prev} cnt={cnt} cap={cap}"
316		);
317		// Safety: sole-writer invariant + bounds-checked above.
318		unsafe { self.buf.store_written(prev + cnt) };
319
320		// Briefly take the kio write lock to wake waiters; drop of `Mut`
321		// triggers kio's notify. Also flip `fin` if we just filled the buffer.
322		if let Ok(mut state) = self.state.write() {
323			if prev + cnt == cap {
324				state.fin = true;
325			}
326		}
327	}
328}
329
330impl Clone for FrameProducer {
331	fn clone(&self) -> Self {
332		Self {
333			info: self.info.clone(),
334			state: self.state.clone(),
335			buf: self.buf.clone(),
336		}
337	}
338}
339
340impl From<Frame> for FrameProducer {
341	fn from(info: Frame) -> Self {
342		FrameProducer::new(info)
343	}
344}
345
346/// Used to consume a frame's worth of data, streaming as bytes arrive.
347#[derive(Clone)]
348pub struct FrameConsumer {
349	info: Frame,
350	state: kio::Consumer<FrameState>,
351	buf: FrameBuf,
352	// Byte offset into the buffer; cloned consumers inherit this offset and
353	// read independently from there.
354	read_idx: usize,
355}
356
357impl std::ops::Deref for FrameConsumer {
358	type Target = Frame;
359
360	fn deref(&self) -> &Self::Target {
361		&self.info
362	}
363}
364
365impl FrameConsumer {
366	// A helper to automatically apply Dropped if the state is closed without an error.
367	fn poll<F, R>(&self, waiter: &kio::Waiter, f: F) -> Poll<Result<R>>
368	where
369		F: Fn(&kio::Ref<'_, FrameState>) -> Poll<Result<R>>,
370	{
371		Poll::Ready(match ready!(self.state.poll(waiter, f)) {
372			Ok(res) => res,
373			Err(state) => Err(state.abort.clone().unwrap_or(Error::Dropped)),
374		})
375	}
376
377	fn snapshot(&self, read_idx: usize) -> Option<Bytes> {
378		// Acquire pairs with the producer's Release on `written`, making the
379		// bytes in `[..written]` visible to this thread.
380		let written = self.buf.written(Ordering::Acquire);
381		if written > read_idx {
382			Some(Bytes::from_owner(self.buf.clone()).slice(read_idx..written))
383		} else {
384			None
385		}
386	}
387
388	/// Poll for all remaining data without blocking.
389	///
390	/// Waits until the frame is finished (written == size); then returns the
391	/// remaining bytes from `read_idx` to the end as a single zero-copy slice.
392	pub fn poll_read_all(&mut self, waiter: &kio::Waiter) -> Poll<Result<Bytes>> {
393		let read_idx = self.read_idx;
394		let res = ready!(self.poll(waiter, |state| {
395			if state.fin {
396				return Poll::Ready(Ok(()));
397			}
398			if let Some(err) = &state.abort {
399				return Poll::Ready(Err(err.clone()));
400			}
401			Poll::Pending
402		}));
403		match res {
404			Ok(()) => {
405				// Frame is finished: written == capacity.
406				let bytes = self
407					.snapshot(read_idx)
408					.unwrap_or_else(|| Bytes::from_owner(self.buf.clone()).slice(read_idx..read_idx));
409				self.read_idx = self.buf.capacity();
410				Poll::Ready(Ok(bytes))
411			}
412			Err(e) => Poll::Ready(Err(e)),
413		}
414	}
415
416	/// Return all of the remaining bytes, blocking until the frame is finished.
417	pub async fn read_all(&mut self) -> Result<Bytes> {
418		kio::wait(|waiter| self.poll_read_all(waiter)).await
419	}
420
421	/// Poll for all remaining bytes (split into a single-element vec for backwards
422	/// compatibility with the previous chunk-based API).
423	pub fn poll_read_all_chunks(&mut self, waiter: &kio::Waiter) -> Poll<Result<Vec<Bytes>>> {
424		let bytes = ready!(self.poll_read_all(waiter)?);
425		Poll::Ready(Ok(if bytes.is_empty() { Vec::new() } else { vec![bytes] }))
426	}
427
428	/// Poll for the next chunk of bytes since the last read.
429	///
430	/// Returns whatever bytes have been written since the consumer's `read_idx` —
431	/// could span multiple producer writes. Returns `None` once the frame is
432	/// finished and all bytes have been consumed.
433	pub fn poll_read_chunk(&mut self, waiter: &kio::Waiter) -> Poll<Result<Option<Bytes>>> {
434		let read_idx = self.read_idx;
435		let res = ready!(self.poll(waiter, |state| {
436			let written = self.buf.written(Ordering::Acquire);
437			if written > read_idx {
438				return Poll::Ready(Ok(Some(written)));
439			}
440			if state.fin {
441				return Poll::Ready(Ok(None));
442			}
443			if let Some(err) = &state.abort {
444				return Poll::Ready(Err(err.clone()));
445			}
446			Poll::Pending
447		}));
448		match res {
449			Ok(Some(written)) => {
450				let bytes = Bytes::from_owner(self.buf.clone()).slice(read_idx..written);
451				self.read_idx = written;
452				Poll::Ready(Ok(Some(bytes)))
453			}
454			Ok(None) => Poll::Ready(Ok(None)),
455			Err(e) => Poll::Ready(Err(e)),
456		}
457	}
458
459	/// Return the next chunk of bytes since the last read.
460	pub async fn read_chunk(&mut self) -> Result<Option<Bytes>> {
461		kio::wait(|waiter| self.poll_read_chunk(waiter)).await
462	}
463
464	/// Poll for the next chunk; for backwards compatibility, wraps
465	/// [Self::poll_read_chunk] in a vec (single element if any data is available).
466	pub fn poll_read_chunks(&mut self, waiter: &kio::Waiter) -> Poll<Result<Vec<Bytes>>> {
467		match ready!(self.poll_read_chunk(waiter)?) {
468			Some(b) => Poll::Ready(Ok(vec![b])),
469			None => Poll::Ready(Ok(Vec::new())),
470		}
471	}
472
473	/// Read the next chunk into a vector (single element if available, empty on eof).
474	pub async fn read_chunks(&mut self) -> Result<Vec<Bytes>> {
475		kio::wait(|waiter| self.poll_read_chunks(waiter)).await
476	}
477}
478
479#[cfg(test)]
480mod test {
481	use super::*;
482	use futures::FutureExt;
483
484	#[test]
485	fn single_chunk_roundtrip() {
486		let mut producer = Frame { size: 5 }.produce();
487		producer.write(Bytes::from_static(b"hello")).unwrap();
488		producer.finish().unwrap();
489
490		let mut consumer = producer.consume();
491		let data = consumer.read_all().now_or_never().unwrap().unwrap();
492		assert_eq!(data, Bytes::from_static(b"hello"));
493	}
494
495	#[test]
496	fn multi_chunk_read_all() {
497		let mut producer = Frame { size: 10 }.produce();
498		producer.write(Bytes::from_static(b"hello")).unwrap();
499		producer.write(Bytes::from_static(b"world")).unwrap();
500		producer.finish().unwrap();
501
502		let mut consumer = producer.consume();
503		let data = consumer.read_all().now_or_never().unwrap().unwrap();
504		assert_eq!(data, Bytes::from_static(b"helloworld"));
505	}
506
507	#[test]
508	fn read_chunk_sequential() {
509		let mut producer = Frame { size: 10 }.produce();
510		producer.write(Bytes::from_static(b"hello")).unwrap();
511		// Each read_chunk returns whatever is new since the last call,
512		// which may span multiple writes.
513		let mut consumer = producer.consume();
514		let c1 = consumer.read_chunk().now_or_never().unwrap().unwrap();
515		assert_eq!(c1, Some(Bytes::from_static(b"hello")));
516
517		producer.write(Bytes::from_static(b"world")).unwrap();
518		producer.finish().unwrap();
519
520		let c2 = consumer.read_chunk().now_or_never().unwrap().unwrap();
521		assert_eq!(c2, Some(Bytes::from_static(b"world")));
522		let c3 = consumer.read_chunk().now_or_never().unwrap().unwrap();
523		assert_eq!(c3, None);
524	}
525
526	#[test]
527	fn read_all_chunks() {
528		let mut producer = Frame { size: 10 }.produce();
529		producer.write(Bytes::from_static(b"hello")).unwrap();
530		producer.write(Bytes::from_static(b"world")).unwrap();
531		producer.finish().unwrap();
532
533		let mut consumer = producer.consume();
534		let chunks = consumer.read_chunks().now_or_never().unwrap().unwrap();
535		assert_eq!(chunks.len(), 1);
536		assert_eq!(chunks[0], Bytes::from_static(b"helloworld"));
537	}
538
539	#[test]
540	fn finish_checks_remaining() {
541		let mut producer = Frame { size: 5 }.produce();
542		producer.write(Bytes::from_static(b"hi")).unwrap();
543		let err = producer.finish().unwrap_err();
544		assert!(matches!(err, Error::WrongSize));
545	}
546
547	#[test]
548	fn write_too_many_bytes() {
549		let mut producer = Frame { size: 3 }.produce();
550		let err = producer.write(Bytes::from_static(b"toolong")).unwrap_err();
551		assert!(matches!(err, Error::WrongSize));
552	}
553
554	#[test]
555	fn abort_propagates() {
556		let mut producer = Frame { size: 5 }.produce();
557		let mut consumer = producer.consume();
558		producer.abort(Error::Cancel).unwrap();
559
560		let err = consumer.read_all().now_or_never().unwrap().unwrap_err();
561		assert!(matches!(err, Error::Cancel));
562	}
563
564	#[test]
565	fn empty_frame() {
566		let mut producer = Frame { size: 0 }.produce();
567		producer.finish().unwrap();
568
569		let mut consumer = producer.consume();
570		let data = consumer.read_all().now_or_never().unwrap().unwrap();
571		assert_eq!(data, Bytes::new());
572	}
573
574	#[tokio::test]
575	async fn pending_then_ready() {
576		let mut producer = Frame { size: 5 }.produce();
577		let mut consumer = producer.consume();
578
579		// Consumer blocks because no data yet.
580		assert!(consumer.read_all().now_or_never().is_none());
581
582		producer.write(Bytes::from_static(b"hello")).unwrap();
583		producer.finish().unwrap();
584
585		let data = consumer.read_all().now_or_never().unwrap().unwrap();
586		assert_eq!(data, Bytes::from_static(b"hello"));
587	}
588
589	#[test]
590	fn buf_mut_roundtrip() {
591		// Exercise the BufMut path that the receive loop uses via `read_buf`.
592		let mut producer = Frame { size: 12 }.produce();
593		assert_eq!(producer.remaining_mut(), 12);
594		producer.put_slice(b"hello");
595		assert_eq!(producer.remaining_mut(), 7);
596		producer.put_slice(b" world!");
597		assert_eq!(producer.remaining_mut(), 0);
598		producer.finish().unwrap();
599
600		let mut consumer = producer.consume();
601		let data = consumer.read_all().now_or_never().unwrap().unwrap();
602		assert_eq!(data, Bytes::from_static(b"hello world!"));
603	}
604
605	#[test]
606	#[should_panic(expected = "advance_mut past frame.size")]
607	fn buf_mut_advance_past_capacity_panics() {
608		let mut producer = Frame { size: 4 }.produce();
609		// Safety violation on purpose: cnt > remaining_mut().
610		unsafe { producer.advance_mut(5) };
611	}
612
613	#[test]
614	fn read_chunk_streams_partial_writes() {
615		let mut producer = Frame { size: 6 }.produce();
616		let mut consumer = producer.consume();
617
618		producer.write(Bytes::from_static(b"foo")).unwrap();
619		let c1 = consumer.read_chunk().now_or_never().unwrap().unwrap();
620		assert_eq!(c1, Some(Bytes::from_static(b"foo")));
621
622		// No new data → pending.
623		assert!(consumer.read_chunk().now_or_never().is_none());
624
625		producer.write(Bytes::from_static(b"bar")).unwrap();
626		producer.finish().unwrap();
627		let c2 = consumer.read_chunk().now_or_never().unwrap().unwrap();
628		assert_eq!(c2, Some(Bytes::from_static(b"bar")));
629		let c3 = consumer.read_chunk().now_or_never().unwrap().unwrap();
630		assert_eq!(c3, None);
631	}
632
633	#[test]
634	fn cloned_consumer_independent_cursor() {
635		let mut producer = Frame { size: 10 }.produce();
636		let mut c1 = producer.consume();
637		producer.write(Bytes::from_static(b"hello")).unwrap();
638
639		// c1 reads the first 5 bytes, then we clone — c2 inherits c1's cursor.
640		let chunk = c1.read_chunk().now_or_never().unwrap().unwrap();
641		assert_eq!(chunk, Some(Bytes::from_static(b"hello")));
642		let mut c2 = c1.clone();
643
644		producer.write(Bytes::from_static(b"world")).unwrap();
645		producer.finish().unwrap();
646
647		// Both consumers now see "world" as their next chunk.
648		let chunk = c1.read_chunk().now_or_never().unwrap().unwrap();
649		assert_eq!(chunk, Some(Bytes::from_static(b"world")));
650		let chunk = c2.read_chunk().now_or_never().unwrap().unwrap();
651		assert_eq!(chunk, Some(Bytes::from_static(b"world")));
652	}
653}