streaming_http_range_client/
test_client.rs1use crate::{HttpClient, Reader, ReaderSource, ReqStats, Result};
2use async_trait::async_trait;
3use std::fmt::{Debug, Formatter};
4use std::ops::{Range, RangeFrom};
5
6pub(crate) struct ByteFormatter<'a>(pub &'a [u8]);
7
8impl Debug for ByteFormatter<'_> {
9 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
10 write!(f, "0x{:02X?}", self.0)
11 }
12}
13
14#[async_trait(?Send)]
16impl ReaderSource for LocalBytesClient {
17 async fn get_byte_range(&self, mut range: Range<u64>) -> Result<Reader> {
18 self.clamp_range(&mut range);
19 let usize_range = range.start as usize..range.end as usize;
20 let range_data = self.bytes[usize_range].to_owned();
21 Ok(Box::pin(std::io::Cursor::new(range_data)))
22 }
23
24 async fn get_byte_range_from(&self, mut range: RangeFrom<u64>) -> Result<Reader> {
25 self.clamp_range_from(&mut range);
26 let usize_range = range.start as usize..;
27 let range_data = self.bytes[usize_range].to_owned();
28 Ok(Box::pin(std::io::Cursor::new(range_data)))
29 }
30
31 fn boxed_clone(&self) -> Box<dyn ReaderSource> {
32 Box::new(self.clone())
33 }
34}
35
36#[derive(Clone)]
37struct LocalBytesClient {
38 bytes: Vec<u8>,
39}
40
41impl LocalBytesClient {
42 fn clamp_range(&self, range: &mut Range<u64>) {
47 let len = self.bytes.len() as u64;
48 if range.start > len {
49 debug!(
50 "clamping request start to filesize {start} -> {len}",
51 start = range.start
52 );
53 range.start = len;
54 }
55 if range.end > len {
56 debug!(
57 "clamping request end to filesize {end} -> {len}",
58 end = range.end
59 );
60 range.end = len;
61 }
62 }
63 fn clamp_range_from(&self, range: &mut RangeFrom<u64>) {
64 let len = self.bytes.len() as u64;
65 if range.start > len {
66 debug!(
67 "clamping request start to filesize {start} -> {len}",
68 start = range.start
69 );
70 range.start = len;
71 }
72 }
73}
74
75impl Debug for LocalBytesClient {
76 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
77 f.debug_struct("LocalBytesClient")
78 .field("bytes", &ByteFormatter(&self.bytes))
79 .finish()
80 }
81}
82
83impl HttpClient {
84 pub fn test_client(data: &[u8]) -> Self {
85 Self {
86 client: Box::new(LocalBytesClient {
87 bytes: data.to_vec(),
88 }),
89 reader: crate::empty(),
90 pos: 0,
91 range: None,
92 stats: ReqStats::default(),
93 }
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use tokio::io::AsyncReadExt;
101
102 #[tokio::test]
103 async fn clamping() {
104 let bytes = [b'a', b'b', b'c'];
105 let mut client = HttpClient::test_client(&bytes);
106
107 client.set_range(1..3).await.unwrap();
108 let mut output = vec![];
109 client.read_to_end(&mut output).await.unwrap();
110 assert_eq!(output, [b'b', b'c']);
111
112 client.set_range(1..4).await.unwrap();
113 let mut output = vec![];
114 client.read_to_end(&mut output).await.unwrap();
115 assert_eq!(output, [b'b', b'c']);
116 }
117}