1use crate::error::{Result, StorageError};
2use htsget_config::types::{Class, Headers, Url};
3use http::HeaderMap;
4use std::borrow::Cow;
5use std::cmp::Ordering;
6use std::fmt;
7use std::fmt::{Display, Formatter};
8use tracing::instrument;
9
10#[derive(Debug, PartialEq, Eq)]
12pub enum DataBlock {
13 Range(BytesPosition),
14 Data(Vec<u8>, Option<Class>),
15}
16
17impl DataBlock {
18 pub fn from_bytes_positions(positions: Vec<BytesPosition>) -> Vec<Self> {
20 BytesPosition::merge_all(positions)
21 .into_iter()
22 .map(DataBlock::Range)
23 .collect()
24 }
25
26 pub fn is_empty(&self) -> bool {
28 match self {
29 DataBlock::Range(range) => range.is_empty(),
30 DataBlock::Data(data, _) => data.is_empty(),
31 }
32 }
33
34 pub fn update_classes(blocks: Vec<Self>) -> Vec<Self> {
37 if blocks.iter().all(|block| match block {
38 DataBlock::Range(range) => range.class.is_some(),
39 DataBlock::Data(_, class) => class.is_some(),
40 }) {
41 blocks
42 } else {
43 blocks
44 .into_iter()
45 .map(|block| match block {
46 DataBlock::Range(range) => DataBlock::Range(range.set_class(None)),
47 DataBlock::Data(data, _) => DataBlock::Data(data, None),
48 })
49 .collect()
50 }
51 }
52}
53
54#[derive(Clone, Debug, Default, PartialEq, Eq)]
60pub struct BytesPosition {
61 start: Option<u64>,
62 end: Option<u64>,
63 class: Option<Class>,
64}
65
66#[derive(Clone, Debug, Default, PartialEq, Eq)]
68pub struct BytesRange {
69 start: Option<u64>,
70 end: Option<u64>,
71}
72
73impl From<&BytesRange> for String {
74 fn from(ranges: &BytesRange) -> Self {
75 if ranges.start.is_none() && ranges.end.is_none() {
76 return "".to_string();
77 }
78 ranges.to_string()
79 }
80}
81
82impl Display for BytesRange {
83 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
84 match (self.start, self.end) {
85 (Some(start), Some(end)) => write!(f, "bytes={start}-{end}"),
86 (Some(0), None) | (None, None) => write!(f, ""),
87 (Some(start), None) => write!(f, "bytes={start}-"),
88 (None, Some(end)) => write!(f, "bytes=0-{end}"),
89 }
90 }
91}
92
93impl TryFrom<&BytesPosition> for BytesRange {
94 type Error = StorageError;
95
96 fn try_from(pos: &BytesPosition) -> Result<Self> {
97 if pos.is_empty() {
98 return Err(StorageError::InternalError(format!(
99 "cannot convert a bytes position with no bytes to a bytes range: {pos:?}"
100 )));
101 }
102
103 Ok(Self::new(pos.start, pos.end.map(|value| value - 1)))
104 }
105}
106
107impl BytesRange {
108 pub fn new(start: Option<u64>, end: Option<u64>) -> Self {
109 Self { start, end }
110 }
111}
112
113#[derive(Clone, Debug, Default)]
115pub struct BytesPositionBuilder {
116 start: Option<u64>,
117 end: Option<u64>,
118 class: Option<Class>,
119}
120
121impl BytesPositionBuilder {
122 pub fn with_start(mut self, start: u64) -> Self {
123 self.start = Some(start);
124 self
125 }
126
127 pub fn set_start(mut self, start: Option<u64>) -> Self {
128 self.start = start;
129 self
130 }
131
132 pub fn with_end(mut self, end: u64) -> Self {
133 self.end = Some(end);
134 self
135 }
136
137 pub fn set_end(mut self, end: Option<u64>) -> Self {
138 self.end = end;
139 self
140 }
141
142 pub fn with_class(mut self, class: Class) -> Self {
143 self.class = Some(class);
144 self
145 }
146
147 pub fn set_class(mut self, class: Option<Class>) -> Self {
148 self.class = class;
149 self
150 }
151
152 pub fn build(self) -> Result<BytesPosition> {
154 if self
155 .end
156 .is_some_and(|end| end < self.start.unwrap_or_default())
157 {
158 return Err(StorageError::InternalError(format!(
159 "invalid bytes position, end `{:?}` is less than start `{:?}`",
160 self.end, self.start
161 )));
162 }
163
164 Ok(BytesPosition {
165 start: self.start,
166 end: self.end,
167 class: self.class,
168 })
169 }
170}
171
172impl BytesPosition {
173 pub fn builder() -> BytesPositionBuilder {
175 BytesPositionBuilder::default()
176 }
177
178 pub fn with_class(self, class: Class) -> Self {
179 self.set_class(Some(class))
180 }
181
182 pub fn set_class(mut self, class: Option<Class>) -> Self {
183 self.class = class;
184 self
185 }
186
187 pub fn get_start(&self) -> Option<u64> {
188 self.start
189 }
190
191 pub fn get_end(&self) -> Option<u64> {
192 self.end
193 }
194
195 pub fn get_class(&self) -> Option<Class> {
196 self.class
197 }
198
199 pub fn is_empty(&self) -> bool {
201 self
202 .end
203 .is_some_and(|end| end == self.start.unwrap_or_default())
204 }
205
206 pub fn overlaps(&self, range: &BytesPosition) -> bool {
207 let cond1 = match (self.start.as_ref(), range.end.as_ref()) {
208 (None, None) | (None, Some(_)) | (Some(_), None) => true,
209 (Some(start), Some(end)) => end >= start,
210 };
211 let cond2 = match (self.end.as_ref(), range.start.as_ref()) {
212 (None, None) | (None, Some(_)) | (Some(_), None) => true,
213 (Some(end), Some(start)) => end >= start,
214 };
215 cond1 && cond2
216 }
217
218 pub fn merge_with(&mut self, position: &BytesPosition) -> &Self {
220 let start = self.start;
221 let end = self.end;
222
223 self.start = match (start.as_ref(), position.start.as_ref()) {
224 (None, None) | (None, Some(_)) | (Some(_), None) => None,
225 (Some(a), Some(b)) => Some(*a.min(b)),
226 };
227 self.end = match (end.as_ref(), position.end.as_ref()) {
228 (None, None) | (None, Some(_)) | (Some(_), None) => None,
229 (Some(a), Some(b)) => Some(*a.max(b)),
230 };
231
232 self.class = match (self.class.as_ref(), position.class.as_ref()) {
233 (Some(Class::Header), Some(Class::Header)) => Some(Class::Header),
234 (Some(Class::Body), Some(Class::Body)) => Some(Class::Body),
235 (_, _) => None,
236 };
237
238 self
239 }
240
241 #[instrument(level = "trace", ret)]
243 pub fn merge_all(mut ranges: Vec<BytesPosition>) -> Vec<BytesPosition> {
244 ranges.retain(|range| !range.is_empty());
245
246 if ranges.len() < 2 {
247 ranges
248 } else {
249 ranges.sort_by(|a, b| {
250 let a_start = a.get_start().unwrap_or(0);
251 let b_start = b.get_start().unwrap_or(0);
252 let start_ord = a_start.cmp(&b_start);
253 if start_ord == Ordering::Equal {
254 let a_end = a.get_end().unwrap_or(u64::MAX);
255 let b_end = b.get_end().unwrap_or(u64::MAX);
256 b_end.cmp(&a_end)
257 } else {
258 start_ord
259 }
260 });
261
262 let mut optimized_ranges = Vec::with_capacity(ranges.len());
263
264 let mut current_range = ranges[0].clone();
265
266 for range in ranges.iter().skip(1) {
267 if current_range.overlaps(range) {
268 current_range.merge_with(range);
269 } else {
270 optimized_ranges.push(current_range);
271 current_range = range.clone();
272 }
273 }
274
275 optimized_ranges.push(current_range);
276
277 optimized_ranges
278 }
279 }
280}
281
282#[derive(Debug, Clone)]
283pub struct GetOptions<'a> {
284 pub(crate) range: BytesPosition,
285 pub(crate) request_headers: Cow<'a, HeaderMap>,
286}
287
288impl<'a> GetOptions<'a> {
289 pub fn new(range: BytesPosition, request_headers: &'a HeaderMap) -> Self {
290 Self {
291 range,
292 request_headers: Cow::Borrowed(request_headers),
293 }
294 }
295
296 pub fn new_with_default_range(request_headers: &'a HeaderMap) -> Self {
297 Self::new(Default::default(), request_headers)
298 }
299
300 pub fn with_max_length(mut self, max_length: u64) -> Result<Self> {
301 self.range = BytesPosition::builder()
302 .with_start(0)
303 .with_end(max_length)
304 .build()?;
305 Ok(self)
306 }
307
308 pub fn with_range(mut self, range: BytesPosition) -> Self {
309 self.range = range;
310 self
311 }
312
313 pub fn range(&self) -> &BytesPosition {
315 &self.range
316 }
317
318 pub fn request_headers(&self) -> &HeaderMap {
320 self.request_headers.as_ref()
321 }
322
323 pub fn set_request_headers(&mut self, request_headers: HeaderMap) {
325 self.request_headers = Cow::Owned(request_headers);
326 }
327}
328
329#[derive(Debug, Clone)]
330pub struct BytesPositionOptions<'a> {
331 pub(crate) positions: Vec<BytesPosition>,
332 pub(crate) headers: &'a HeaderMap,
333}
334
335impl<'a> BytesPositionOptions<'a> {
336 pub fn new(positions: Vec<BytesPosition>, headers: &'a HeaderMap) -> Self {
337 Self { positions, headers }
338 }
339
340 pub fn headers(&self) -> &'a HeaderMap {
342 self.headers
343 }
344
345 pub fn positions(&self) -> &Vec<BytesPosition> {
346 &self.positions
347 }
348
349 pub fn into_inner(self) -> Vec<BytesPosition> {
351 self.positions
352 }
353
354 pub fn merge_all(mut self) -> Self {
356 self.positions = BytesPosition::merge_all(self.positions);
357 self
358 }
359}
360
361#[derive(Debug, Clone)]
362pub struct RangeUrlOptions<'a> {
363 range: BytesPosition,
364 response_headers: &'a HeaderMap,
365}
366
367impl<'a> RangeUrlOptions<'a> {
368 pub fn new(range: BytesPosition, response_headers: &'a HeaderMap) -> Self {
369 Self {
370 range,
371 response_headers,
372 }
373 }
374
375 pub fn new_with_default_range(request_headers: &'a HeaderMap) -> Self {
376 Self::new(Default::default(), request_headers)
377 }
378
379 pub fn with_range(mut self, range: BytesPosition) -> Self {
380 self.range = range;
381 self
382 }
383
384 pub fn apply(self, url: Url) -> Result<Url> {
385 let range: String = String::from(&BytesRange::try_from(self.range())?);
386
387 let url = if range.is_empty() {
388 url
389 } else {
390 url.add_headers(Headers::default().with_header("Range", range))
391 };
392
393 Ok(url.set_class(self.range().class))
394 }
395
396 pub fn range(&self) -> &BytesPosition {
398 &self.range
399 }
400
401 pub fn response_headers(&self) -> &'a HeaderMap {
403 self.response_headers
404 }
405}
406
407#[derive(Debug, Clone)]
409pub struct HeadOptions<'a> {
410 request_headers: &'a HeaderMap,
411}
412
413impl<'a> HeadOptions<'a> {
414 pub fn new(request_headers: &'a HeaderMap) -> Self {
416 Self { request_headers }
417 }
418
419 pub fn request_headers(&self) -> &'a HeaderMap {
421 self.request_headers
422 }
423}
424
425impl<'a> From<&'a GetOptions<'a>> for HeadOptions<'a> {
426 fn from(options: &'a GetOptions<'a>) -> Self {
427 Self::new(options.request_headers())
428 }
429}
430
431#[cfg(test)]
432mod tests {
433 use std::collections::HashMap;
434
435 use super::*;
436
437 #[test]
438 fn bytes_range_overlapping_and_merge() {
439 let test_cases = vec![
440 (
441 BytesPosition::builder().with_end(2).build().unwrap(),
442 BytesPosition::builder()
443 .with_start(3)
444 .with_end(5)
445 .build()
446 .unwrap(),
447 None,
448 ),
449 (
450 BytesPosition::builder().with_end(2).build().unwrap(),
451 BytesPosition::builder().with_start(3).build().unwrap(),
452 None,
453 ),
454 (
455 BytesPosition::builder().with_end(2).build().unwrap(),
456 BytesPosition::builder()
457 .with_start(2)
458 .with_end(4)
459 .build()
460 .unwrap(),
461 Some(BytesPosition::builder().with_end(4).build().unwrap()),
462 ),
463 (
464 BytesPosition::builder().with_end(2).build().unwrap(),
465 BytesPosition::builder().with_start(2).build().unwrap(),
466 Some(BytesPosition::builder().build().unwrap()),
467 ),
468 (
469 BytesPosition::builder().with_end(2).build().unwrap(),
470 BytesPosition::builder()
471 .with_start(1)
472 .with_end(3)
473 .build()
474 .unwrap(),
475 Some(BytesPosition::builder().with_end(3).build().unwrap()),
476 ),
477 (
478 BytesPosition::builder().with_end(2).build().unwrap(),
479 BytesPosition::builder().with_start(1).build().unwrap(),
480 Some(BytesPosition::builder().build().unwrap()),
481 ),
482 (
483 BytesPosition::builder().with_end(2).build().unwrap(),
484 BytesPosition::builder()
485 .with_start(0)
486 .with_end(2)
487 .build()
488 .unwrap(),
489 Some(BytesPosition::builder().with_end(2).build().unwrap()),
490 ),
491 (
492 BytesPosition::builder().with_end(2).build().unwrap(),
493 BytesPosition::builder().with_end(2).build().unwrap(),
494 Some(BytesPosition::builder().with_end(2).build().unwrap()),
495 ),
496 (
497 BytesPosition::builder().with_end(2).build().unwrap(),
498 BytesPosition::builder()
499 .with_start(0)
500 .with_end(1)
501 .build()
502 .unwrap(),
503 Some(BytesPosition::builder().with_end(2).build().unwrap()),
504 ),
505 (
506 BytesPosition::builder().with_end(2).build().unwrap(),
507 BytesPosition::builder().with_end(1).build().unwrap(),
508 Some(BytesPosition::builder().with_end(2).build().unwrap()),
509 ),
510 (
511 BytesPosition::builder().with_end(2).build().unwrap(),
512 BytesPosition::builder().build().unwrap(),
513 Some(BytesPosition::builder().build().unwrap()),
514 ),
515 (
516 BytesPosition::builder()
517 .with_start(2)
518 .with_end(4)
519 .build()
520 .unwrap(),
521 BytesPosition::builder()
522 .with_start(6)
523 .with_end(8)
524 .build()
525 .unwrap(),
526 None,
527 ),
528 (
529 BytesPosition::builder()
530 .with_start(2)
531 .with_end(4)
532 .build()
533 .unwrap(),
534 BytesPosition::builder().with_start(6).build().unwrap(),
535 None,
536 ),
537 (
538 BytesPosition::builder()
539 .with_start(2)
540 .with_end(4)
541 .build()
542 .unwrap(),
543 BytesPosition::builder()
544 .with_start(4)
545 .with_end(6)
546 .build()
547 .unwrap(),
548 Some(
549 BytesPosition::builder()
550 .with_start(2)
551 .with_end(6)
552 .build()
553 .unwrap(),
554 ),
555 ),
556 (
557 BytesPosition::builder()
558 .with_start(2)
559 .with_end(4)
560 .build()
561 .unwrap(),
562 BytesPosition::builder().with_start(4).build().unwrap(),
563 Some(BytesPosition::builder().with_start(2).build().unwrap()),
564 ),
565 (
566 BytesPosition::builder()
567 .with_start(2)
568 .with_end(4)
569 .build()
570 .unwrap(),
571 BytesPosition::builder()
572 .with_start(3)
573 .with_end(5)
574 .build()
575 .unwrap(),
576 Some(
577 BytesPosition::builder()
578 .with_start(2)
579 .with_end(5)
580 .build()
581 .unwrap(),
582 ),
583 ),
584 (
585 BytesPosition::builder()
586 .with_start(2)
587 .with_end(4)
588 .build()
589 .unwrap(),
590 BytesPosition::builder().with_start(3).build().unwrap(),
591 Some(BytesPosition::builder().with_start(2).build().unwrap()),
592 ),
593 (
594 BytesPosition::builder()
595 .with_start(2)
596 .with_end(4)
597 .build()
598 .unwrap(),
599 BytesPosition::builder()
600 .with_start(2)
601 .with_end(3)
602 .build()
603 .unwrap(),
604 Some(
605 BytesPosition::builder()
606 .with_start(2)
607 .with_end(4)
608 .build()
609 .unwrap(),
610 ),
611 ),
612 (
613 BytesPosition::builder()
614 .with_start(2)
615 .with_end(4)
616 .build()
617 .unwrap(),
618 BytesPosition::builder().with_end(3).build().unwrap(),
619 Some(BytesPosition::builder().with_end(4).build().unwrap()),
620 ),
621 (
622 BytesPosition::builder()
623 .with_start(2)
624 .with_end(4)
625 .build()
626 .unwrap(),
627 BytesPosition::builder()
628 .with_start(1)
629 .with_end(3)
630 .build()
631 .unwrap(),
632 Some(
633 BytesPosition::builder()
634 .with_start(1)
635 .with_end(4)
636 .build()
637 .unwrap(),
638 ),
639 ),
640 (
641 BytesPosition::builder()
642 .with_start(2)
643 .with_end(4)
644 .build()
645 .unwrap(),
646 BytesPosition::builder().with_end(3).build().unwrap(),
647 Some(BytesPosition::builder().with_end(4).build().unwrap()),
648 ),
649 (
650 BytesPosition::builder()
651 .with_start(2)
652 .with_end(4)
653 .build()
654 .unwrap(),
655 BytesPosition::builder()
656 .with_start(0)
657 .with_end(2)
658 .build()
659 .unwrap(),
660 Some(
661 BytesPosition::builder()
662 .with_start(0)
663 .with_end(4)
664 .build()
665 .unwrap(),
666 ),
667 ),
668 (
669 BytesPosition::builder()
670 .with_start(2)
671 .with_end(4)
672 .build()
673 .unwrap(),
674 BytesPosition::builder().with_end(2).build().unwrap(),
675 Some(BytesPosition::builder().with_end(4).build().unwrap()),
676 ),
677 (
678 BytesPosition::builder()
679 .with_start(2)
680 .with_end(4)
681 .build()
682 .unwrap(),
683 BytesPosition::builder()
684 .with_start(0)
685 .with_end(1)
686 .build()
687 .unwrap(),
688 None,
689 ),
690 (
691 BytesPosition::builder()
692 .with_start(2)
693 .with_end(4)
694 .build()
695 .unwrap(),
696 BytesPosition::builder().with_end(1).build().unwrap(),
697 None,
698 ),
699 (
700 BytesPosition::builder()
701 .with_start(2)
702 .with_end(4)
703 .build()
704 .unwrap(),
705 BytesPosition::builder().build().unwrap(),
706 Some(BytesPosition::builder().build().unwrap()),
707 ),
708 (
709 BytesPosition::builder().with_start(2).build().unwrap(),
710 BytesPosition::builder()
711 .with_start(4)
712 .with_end(6)
713 .build()
714 .unwrap(),
715 Some(BytesPosition::builder().with_start(2).build().unwrap()),
716 ),
717 (
718 BytesPosition::builder().with_start(2).build().unwrap(),
719 BytesPosition::builder().with_start(4).build().unwrap(),
720 Some(BytesPosition::builder().with_start(2).build().unwrap()),
721 ),
722 (
723 BytesPosition::builder().with_start(2).build().unwrap(),
724 BytesPosition::builder()
725 .with_start(2)
726 .with_end(4)
727 .build()
728 .unwrap(),
729 Some(BytesPosition::builder().with_start(2).build().unwrap()),
730 ),
731 (
732 BytesPosition::builder().with_start(2).build().unwrap(),
733 BytesPosition::builder().with_start(2).build().unwrap(),
734 Some(BytesPosition::builder().with_start(2).build().unwrap()),
735 ),
736 (
737 BytesPosition::builder().with_start(2).build().unwrap(),
738 BytesPosition::builder()
739 .with_start(1)
740 .with_end(3)
741 .build()
742 .unwrap(),
743 Some(BytesPosition::builder().with_start(1).build().unwrap()),
744 ),
745 (
746 BytesPosition::builder().with_start(2).build().unwrap(),
747 BytesPosition::builder().with_end(3).build().unwrap(),
748 Some(BytesPosition::builder().build().unwrap()),
749 ),
750 (
751 BytesPosition::builder().with_start(2).build().unwrap(),
752 BytesPosition::builder()
753 .with_start(0)
754 .with_end(2)
755 .build()
756 .unwrap(),
757 Some(BytesPosition::builder().with_start(0).build().unwrap()),
758 ),
759 (
760 BytesPosition::builder().with_start(2).build().unwrap(),
761 BytesPosition::builder().with_end(2).build().unwrap(),
762 Some(BytesPosition::builder().build().unwrap()),
763 ),
764 (
765 BytesPosition::builder().with_start(2).build().unwrap(),
766 BytesPosition::builder()
767 .with_start(0)
768 .with_end(1)
769 .build()
770 .unwrap(),
771 None,
772 ),
773 (
774 BytesPosition::builder().with_start(2).build().unwrap(),
775 BytesPosition::builder().with_end(1).build().unwrap(),
776 None,
777 ),
778 (
779 BytesPosition::builder().with_start(2).build().unwrap(),
780 BytesPosition::builder().build().unwrap(),
781 Some(BytesPosition::builder().build().unwrap()),
782 ),
783 (
784 BytesPosition::builder().build().unwrap(),
785 BytesPosition::builder().build().unwrap(),
786 Some(BytesPosition::builder().build().unwrap()),
787 ),
788 ];
789
790 for (index, (a, b, expected)) in test_cases.iter().enumerate() {
791 println!("Test case {index}");
792 println!(" {a:?}");
793 println!(" {b:?}");
794 println!(" {expected:?}");
795
796 if a.overlaps(b) {
797 assert_eq!(*a.clone().merge_with(b), expected.clone().unwrap());
798 } else {
799 assert!(expected.is_none())
800 }
801 }
802 }
803
804 #[test]
805 fn bytes_range_merge_all_when_list_is_empty() {
806 assert_eq!(BytesPosition::merge_all(Vec::new()), Vec::new());
807 }
808
809 #[test]
810 fn bytes_range_merge_all_removes_empty_positions() {
811 assert_eq!(
812 BytesPosition::merge_all(vec![
813 BytesPosition::builder()
814 .with_start(0)
815 .with_end(0)
816 .build()
817 .unwrap(),
818 BytesPosition::builder()
819 .with_start(5)
820 .with_end(5)
821 .build()
822 .unwrap(),
823 BytesPosition::builder()
824 .with_start(1)
825 .with_end(2)
826 .build()
827 .unwrap(),
828 ]),
829 vec![
830 BytesPosition::builder()
831 .with_start(1)
832 .with_end(2)
833 .build()
834 .unwrap()
835 ]
836 );
837 }
838
839 #[test]
840 fn bytes_position_is_empty() {
841 assert!(
842 BytesPosition::builder()
843 .with_start(0)
844 .with_end(0)
845 .build()
846 .unwrap()
847 .is_empty()
848 );
849 assert!(
850 BytesPosition::builder()
851 .with_end(0)
852 .build()
853 .unwrap()
854 .is_empty()
855 );
856 assert!(
857 !BytesPosition::builder()
858 .with_start(0)
859 .with_end(1)
860 .build()
861 .unwrap()
862 .is_empty()
863 );
864 assert!(
865 !BytesPosition::builder()
866 .with_start(1)
867 .build()
868 .unwrap()
869 .is_empty()
870 );
871 assert!(!BytesPosition::builder().build().unwrap().is_empty());
872 }
873
874 #[test]
875 fn bytes_position_end_less_than_start() {
876 assert!(
877 BytesPosition::builder()
878 .with_start(2)
879 .with_end(1)
880 .build()
881 .is_err()
882 );
883 assert!(BytesPosition::builder().with_end(1).build().is_ok());
884 assert!(
885 BytesPosition::builder()
886 .with_end(2)
887 .with_start(3)
888 .build()
889 .is_err()
890 );
891 assert!(
892 BytesPosition::builder()
893 .with_start(3)
894 .with_end(2)
895 .build()
896 .is_err()
897 );
898 assert!(
899 BytesPosition::builder()
900 .with_start(3)
901 .set_end(Some(2))
902 .build()
903 .is_err()
904 );
905 }
906
907 #[test]
908 fn bytes_position_builder() {
909 let result = BytesPosition::builder()
910 .with_end(2)
911 .with_start(5)
912 .with_end(10)
913 .build();
914 assert_eq!(
915 result.unwrap(),
916 BytesPosition::builder()
917 .with_start(5)
918 .with_end(10)
919 .build()
920 .unwrap()
921 );
922 }
923
924 #[test]
925 fn bytes_range_try_from_empty_position() {
926 assert!(
927 BytesRange::try_from(
928 &BytesPosition::builder()
929 .with_start(5)
930 .with_end(5)
931 .build()
932 .unwrap()
933 )
934 .is_err()
935 );
936 assert!(BytesRange::try_from(&BytesPosition::builder().with_end(0).build().unwrap()).is_err());
937 }
938
939 #[test]
940 fn bytes_range_merge_all_when_list_has_one_range() {
941 assert_eq!(
942 BytesPosition::merge_all(vec![BytesPosition::default()]),
943 vec![BytesPosition::default()]
944 );
945 }
946
947 #[test]
948 fn bytes_position_merge_class_header() {
949 assert_eq!(
950 BytesPosition::merge_all(vec![
951 BytesPosition::builder()
952 .with_end(1)
953 .with_class(Class::Header)
954 .build()
955 .unwrap(),
956 BytesPosition::builder()
957 .with_end(2)
958 .with_class(Class::Header)
959 .build()
960 .unwrap()
961 ]),
962 vec![
963 BytesPosition::builder()
964 .with_end(2)
965 .with_class(Class::Header)
966 .build()
967 .unwrap()
968 ]
969 );
970 }
971
972 #[test]
973 fn bytes_position_merge_class_body() {
974 assert_eq!(
975 BytesPosition::merge_all(vec![
976 BytesPosition::builder()
977 .with_end(1)
978 .with_class(Class::Body)
979 .build()
980 .unwrap(),
981 BytesPosition::builder()
982 .with_end(3)
983 .with_class(Class::Body)
984 .build()
985 .unwrap()
986 ]),
987 vec![
988 BytesPosition::builder()
989 .with_end(3)
990 .with_class(Class::Body)
991 .build()
992 .unwrap()
993 ]
994 );
995 }
996
997 #[test]
998 fn bytes_position_merge_class_none() {
999 assert_eq!(
1000 BytesPosition::merge_all(vec![
1001 BytesPosition::builder()
1002 .with_start(1)
1003 .with_end(2)
1004 .build()
1005 .unwrap(),
1006 BytesPosition::builder()
1007 .with_start(2)
1008 .with_end(3)
1009 .build()
1010 .unwrap()
1011 ]),
1012 vec![
1013 BytesPosition::builder()
1014 .with_start(1)
1015 .with_end(3)
1016 .build()
1017 .unwrap()
1018 ]
1019 );
1020 }
1021
1022 #[test]
1023 fn bytes_position_merge_class_different() {
1024 assert_eq!(
1025 BytesPosition::merge_all(vec![
1026 BytesPosition::builder()
1027 .with_start(1)
1028 .with_end(2)
1029 .with_class(Class::Header)
1030 .build()
1031 .unwrap(),
1032 BytesPosition::builder()
1033 .with_start(2)
1034 .with_end(3)
1035 .with_class(Class::Body)
1036 .build()
1037 .unwrap()
1038 ]),
1039 vec![
1040 BytesPosition::builder()
1041 .with_start(1)
1042 .with_end(3)
1043 .build()
1044 .unwrap()
1045 ]
1046 );
1047 }
1048
1049 #[test]
1050 fn bytes_range_merge_all_when_list_has_many_ranges() {
1051 let ranges = vec![
1052 BytesPosition::builder().with_end(1).build().unwrap(),
1053 BytesPosition::builder()
1054 .with_start(1)
1055 .with_end(2)
1056 .build()
1057 .unwrap(),
1058 BytesPosition::builder()
1059 .with_start(5)
1060 .with_end(6)
1061 .build()
1062 .unwrap(),
1063 BytesPosition::builder()
1064 .with_start(5)
1065 .with_end(8)
1066 .build()
1067 .unwrap(),
1068 BytesPosition::builder()
1069 .with_start(6)
1070 .with_end(7)
1071 .build()
1072 .unwrap(),
1073 BytesPosition::builder()
1074 .with_start(4)
1075 .with_end(5)
1076 .build()
1077 .unwrap(),
1078 BytesPosition::builder()
1079 .with_start(3)
1080 .with_end(6)
1081 .build()
1082 .unwrap(),
1083 BytesPosition::builder()
1084 .with_start(10)
1085 .with_end(12)
1086 .build()
1087 .unwrap(),
1088 BytesPosition::builder()
1089 .with_start(10)
1090 .with_end(12)
1091 .build()
1092 .unwrap(),
1093 BytesPosition::builder()
1094 .with_start(10)
1095 .with_end(14)
1096 .build()
1097 .unwrap(),
1098 BytesPosition::builder()
1099 .with_start(14)
1100 .with_end(15)
1101 .build()
1102 .unwrap(),
1103 BytesPosition::builder()
1104 .with_start(12)
1105 .with_end(16)
1106 .build()
1107 .unwrap(),
1108 BytesPosition::builder()
1109 .with_start(17)
1110 .with_end(19)
1111 .build()
1112 .unwrap(),
1113 BytesPosition::builder()
1114 .with_start(21)
1115 .with_end(23)
1116 .build()
1117 .unwrap(),
1118 BytesPosition::builder()
1119 .with_start(18)
1120 .with_end(22)
1121 .build()
1122 .unwrap(),
1123 BytesPosition::builder().with_start(24).build().unwrap(),
1124 BytesPosition::builder()
1125 .with_start(24)
1126 .with_end(30)
1127 .build()
1128 .unwrap(),
1129 BytesPosition::builder()
1130 .with_start(31)
1131 .with_end(33)
1132 .build()
1133 .unwrap(),
1134 BytesPosition::builder().with_start(35).build().unwrap(),
1135 ];
1136
1137 let expected_ranges = vec![
1138 BytesPosition::builder().with_end(2).build().unwrap(),
1139 BytesPosition::builder()
1140 .with_start(3)
1141 .with_end(8)
1142 .build()
1143 .unwrap(),
1144 BytesPosition::builder()
1145 .with_start(10)
1146 .with_end(16)
1147 .build()
1148 .unwrap(),
1149 BytesPosition::builder()
1150 .with_start(17)
1151 .with_end(23)
1152 .build()
1153 .unwrap(),
1154 BytesPosition::builder().with_start(24).build().unwrap(),
1155 ];
1156
1157 assert_eq!(BytesPosition::merge_all(ranges), expected_ranges);
1158 }
1159
1160 #[test]
1161 fn bytes_position_new() {
1162 let result = BytesPosition::builder()
1163 .with_start(1)
1164 .with_end(2)
1165 .with_class(Class::Header)
1166 .build()
1167 .unwrap();
1168 assert_eq!(result.start, Some(1));
1169 assert_eq!(result.end, Some(2));
1170 assert_eq!(result.class, Some(Class::Header));
1171 }
1172
1173 #[test]
1174 fn bytes_position_with_start() {
1175 let result = BytesPosition::builder().with_start(1).build().unwrap();
1176 assert_eq!(result.start, Some(1));
1177 }
1178
1179 #[test]
1180 fn bytes_position_with_end() {
1181 let result = BytesPosition::builder().with_end(1).build().unwrap();
1182 assert_eq!(result.end, Some(1));
1183 }
1184
1185 #[test]
1186 fn bytes_position_with_class() {
1187 let result = BytesPosition::default().with_class(Class::Header);
1188 assert_eq!(result.class, Some(Class::Header));
1189 }
1190
1191 #[test]
1192 fn bytes_position_set_class() {
1193 let result = BytesPosition::default().set_class(Some(Class::Header));
1194 assert_eq!(result.class, Some(Class::Header));
1195 }
1196
1197 #[test]
1198 fn data_block_update_classes_all_some() {
1199 let blocks = DataBlock::update_classes(vec![
1200 DataBlock::Range(
1201 BytesPosition::builder()
1202 .with_end(1)
1203 .with_class(Class::Body)
1204 .build()
1205 .unwrap(),
1206 ),
1207 DataBlock::Data(vec![], Some(Class::Header)),
1208 ]);
1209 for block in blocks {
1210 let class = match block {
1211 DataBlock::Range(pos) => pos.class,
1212 DataBlock::Data(_, class) => class,
1213 };
1214 assert!(class.is_some());
1215 }
1216 }
1217
1218 #[test]
1219 fn data_block_update_classes_one_none() {
1220 let blocks = DataBlock::update_classes(vec![
1221 DataBlock::Range(
1222 BytesPosition::builder()
1223 .with_end(1)
1224 .with_class(Class::Body)
1225 .build()
1226 .unwrap(),
1227 ),
1228 DataBlock::Data(vec![], None),
1229 ]);
1230 for block in blocks {
1231 let class = match block {
1232 DataBlock::Range(pos) => pos.class,
1233 DataBlock::Data(_, class) => class,
1234 };
1235 assert!(class.is_none());
1236 }
1237 }
1238
1239 #[test]
1240 fn data_block_from_bytes_positions() {
1241 let blocks = DataBlock::from_bytes_positions(vec![
1242 BytesPosition::builder().with_end(1).build().unwrap(),
1243 BytesPosition::builder()
1244 .with_start(1)
1245 .with_end(2)
1246 .build()
1247 .unwrap(),
1248 ]);
1249 assert_eq!(
1250 blocks,
1251 vec![DataBlock::Range(
1252 BytesPosition::builder().with_end(2).build().unwrap()
1253 )]
1254 );
1255 }
1256
1257 #[test]
1258 fn data_block_from_empty_bytes_positions() {
1259 let blocks = DataBlock::from_bytes_positions(vec![
1260 BytesPosition::builder()
1261 .with_start(0)
1262 .with_end(0)
1263 .build()
1264 .unwrap(),
1265 ]);
1266 assert_eq!(blocks, vec![]);
1267 }
1268
1269 #[test]
1270 fn data_block_is_empty() {
1271 assert!(
1272 DataBlock::Range(
1273 BytesPosition::builder()
1274 .with_start(0)
1275 .with_end(0)
1276 .build()
1277 .unwrap()
1278 )
1279 .is_empty()
1280 );
1281 assert!(DataBlock::Data(vec![], None).is_empty());
1282 assert!(
1283 !DataBlock::Range(
1284 BytesPosition::builder()
1285 .with_start(0)
1286 .with_end(1)
1287 .build()
1288 .unwrap()
1289 )
1290 .is_empty()
1291 );
1292 assert!(!DataBlock::Data(vec![0], None).is_empty());
1293 }
1294
1295 #[test]
1296 fn byte_range_from_byte_position() {
1297 let result = BytesRange::try_from(
1298 &BytesPosition::builder()
1299 .with_start(5)
1300 .with_end(10)
1301 .build()
1302 .unwrap(),
1303 )
1304 .unwrap();
1305 let expected = BytesRange::new(Some(5), Some(9));
1306 assert_eq!(result, expected);
1307 }
1308
1309 #[test]
1310 fn get_options_with_max_length() {
1311 let request_headers = Default::default();
1312 let result = GetOptions::new_with_default_range(&request_headers)
1313 .with_max_length(1)
1314 .unwrap();
1315 assert_eq!(
1316 result.range(),
1317 &BytesPosition::builder()
1318 .with_start(0)
1319 .with_end(1)
1320 .build()
1321 .unwrap()
1322 );
1323 }
1324
1325 #[test]
1326 fn get_options_with_range() {
1327 let request_headers = Default::default();
1328 let result = GetOptions::new_with_default_range(&request_headers).with_range(
1329 BytesPosition::builder()
1330 .with_start(5)
1331 .with_end(11)
1332 .with_class(Class::Header)
1333 .build()
1334 .unwrap(),
1335 );
1336 assert_eq!(
1337 result.range(),
1338 &BytesPosition::builder()
1339 .with_start(5)
1340 .with_end(11)
1341 .with_class(Class::Header)
1342 .build()
1343 .unwrap()
1344 );
1345 }
1346
1347 #[test]
1348 fn url_options_with_range() {
1349 let request_headers = Default::default();
1350 let result = RangeUrlOptions::new_with_default_range(&request_headers).with_range(
1351 BytesPosition::builder()
1352 .with_start(5)
1353 .with_end(11)
1354 .with_class(Class::Header)
1355 .build()
1356 .unwrap(),
1357 );
1358 assert_eq!(
1359 result.range(),
1360 &BytesPosition::builder()
1361 .with_start(5)
1362 .with_end(11)
1363 .with_class(Class::Header)
1364 .build()
1365 .unwrap()
1366 );
1367 }
1368
1369 #[test]
1370 fn url_options_apply_with_bytes_range() {
1371 let result = RangeUrlOptions::new(
1372 BytesPosition::builder()
1373 .with_start(5)
1374 .with_end(11)
1375 .with_class(Class::Header)
1376 .build()
1377 .unwrap(),
1378 &Default::default(),
1379 )
1380 .apply(Url::new(""))
1381 .unwrap();
1382 println!("{result:?}");
1383 assert_eq!(
1384 result,
1385 Url::new("")
1386 .with_headers(Headers::new(HashMap::new()).with_header("Range", "bytes=5-10"))
1387 .with_class(Class::Header)
1388 );
1389 }
1390
1391 #[test]
1392 fn url_options_apply_no_bytes_range() {
1393 let result = RangeUrlOptions::new_with_default_range(&Default::default())
1394 .apply(Url::new(""))
1395 .unwrap();
1396 assert_eq!(result, Url::new(""));
1397 }
1398
1399 #[test]
1400 fn url_options_apply_with_headers() {
1401 let result = RangeUrlOptions::new(
1402 BytesPosition::builder()
1403 .with_start(5)
1404 .with_end(11)
1405 .with_class(Class::Header)
1406 .build()
1407 .unwrap(),
1408 &Default::default(),
1409 )
1410 .apply(Url::new("").with_headers(Headers::default().with_header("header", "value")))
1411 .unwrap();
1412 println!("{result:?}");
1413
1414 assert_eq!(
1415 result,
1416 Url::new("")
1417 .with_headers(
1418 Headers::new(HashMap::new())
1419 .with_header("Range", "bytes=5-10")
1420 .with_header("header", "value")
1421 )
1422 .with_class(Class::Header)
1423 );
1424 }
1425}