htsget_storage/
types.rs

1use htsget_config::types::{Class, Headers, Url};
2use http::HeaderMap;
3use std::cmp::Ordering;
4use std::fmt;
5use std::fmt::{Display, Formatter};
6use tracing::instrument;
7
8/// A DataBlock is either a range of bytes, or a data blob that gets transformed into a data uri.
9#[derive(Debug, PartialEq, Eq)]
10pub enum DataBlock {
11  Range(BytesPosition),
12  Data(Vec<u8>, Option<Class>),
13}
14
15impl DataBlock {
16  /// Convert a vec of bytes positions to a vec of data blocks. Merges bytes positions.
17  pub fn from_bytes_positions(positions: Vec<BytesPosition>) -> Vec<Self> {
18    BytesPosition::merge_all(positions)
19      .into_iter()
20      .map(DataBlock::Range)
21      .collect()
22  }
23
24  /// Update the classes of all blocks so that they all contain a class, or None. Does not merge
25  /// byte positions.
26  pub fn update_classes(blocks: Vec<Self>) -> Vec<Self> {
27    if blocks.iter().all(|block| match block {
28      DataBlock::Range(range) => range.class.is_some(),
29      DataBlock::Data(_, class) => class.is_some(),
30    }) {
31      blocks
32    } else {
33      blocks
34        .into_iter()
35        .map(|block| match block {
36          DataBlock::Range(range) => DataBlock::Range(range.set_class(None)),
37          DataBlock::Data(data, _) => DataBlock::Data(data, None),
38        })
39        .collect()
40    }
41  }
42}
43
44/// A byte position has an inclusive start value, and an exclusive end value. This is analogous to
45/// query start and end parameters. The class represents the class type for this byte position when
46/// formatted into url responses. The class is set to `Header` for byte positions containing only
47/// header bytes, `Body` for byte positions containing only body bytes, and None for byte positions
48/// with a mix of header and body bytes.
49#[derive(Clone, Debug, Default, PartialEq, Eq)]
50pub struct BytesPosition {
51  pub(crate) start: Option<u64>,
52  pub(crate) end: Option<u64>,
53  pub(crate) class: Option<Class>,
54}
55
56/// A bytes range has an inclusive start and end value. This is analogous to http bytes ranges.
57#[derive(Clone, Debug, Default, PartialEq, Eq)]
58pub struct BytesRange {
59  start: Option<u64>,
60  end: Option<u64>,
61}
62
63impl From<&BytesRange> for String {
64  fn from(ranges: &BytesRange) -> Self {
65    if ranges.start.is_none() && ranges.end.is_none() {
66      return "".to_string();
67    }
68    ranges.to_string()
69  }
70}
71
72impl Display for BytesRange {
73  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
74    let start = self
75      .start
76      .map(|start| start.to_string())
77      .unwrap_or_else(|| "0".to_string());
78    let end = self.end.map(|end| end.to_string()).unwrap_or_default();
79    write!(f, "bytes={start}-{end}")
80  }
81}
82
83impl From<&BytesPosition> for BytesRange {
84  fn from(pos: &BytesPosition) -> Self {
85    Self::new(pos.start, pos.end.map(|value| value - 1))
86  }
87}
88
89impl BytesRange {
90  pub fn new(start: Option<u64>, end: Option<u64>) -> Self {
91    Self { start, end }
92  }
93}
94
95impl BytesPosition {
96  pub fn new(start: Option<u64>, end: Option<u64>, class: Option<Class>) -> Self {
97    Self { start, end, class }
98  }
99
100  pub fn with_start(mut self, start: u64) -> Self {
101    self.start = Some(start);
102    self
103  }
104
105  pub fn with_end(mut self, end: u64) -> Self {
106    self.end = Some(end);
107    self
108  }
109
110  pub fn with_class(self, class: Class) -> Self {
111    self.set_class(Some(class))
112  }
113
114  pub fn set_class(mut self, class: Option<Class>) -> Self {
115    self.class = class;
116    self
117  }
118
119  pub fn get_start(&self) -> Option<u64> {
120    self.start
121  }
122
123  pub fn get_end(&self) -> Option<u64> {
124    self.end
125  }
126
127  pub fn overlaps(&self, range: &BytesPosition) -> bool {
128    let cond1 = match (self.start.as_ref(), range.end.as_ref()) {
129      (None, None) | (None, Some(_)) | (Some(_), None) => true,
130      (Some(start), Some(end)) => end >= start,
131    };
132    let cond2 = match (self.end.as_ref(), range.start.as_ref()) {
133      (None, None) | (None, Some(_)) | (Some(_), None) => true,
134      (Some(end), Some(start)) => end >= start,
135    };
136    cond1 && cond2
137  }
138
139  /// Merges position with the current BytesPosition, assuming that the two positions overlap.
140  pub fn merge_with(&mut self, position: &BytesPosition) -> &Self {
141    let start = self.start;
142    let end = self.end;
143
144    self.start = match (start.as_ref(), position.start.as_ref()) {
145      (None, None) | (None, Some(_)) | (Some(_), None) => None,
146      (Some(a), Some(b)) => Some(*a.min(b)),
147    };
148    self.end = match (end.as_ref(), position.end.as_ref()) {
149      (None, None) | (None, Some(_)) | (Some(_), None) => None,
150      (Some(a), Some(b)) => Some(*a.max(b)),
151    };
152
153    self.class = match (self.class.as_ref(), position.class.as_ref()) {
154      (Some(Class::Header), Some(Class::Header)) => Some(Class::Header),
155      (Some(Class::Body), Some(Class::Body)) => Some(Class::Body),
156      (_, _) => None,
157    };
158
159    self
160  }
161
162  /// Merge ranges, assuming ending byte ranges are exclusive.
163  #[instrument(level = "trace", ret)]
164  pub fn merge_all(mut ranges: Vec<BytesPosition>) -> Vec<BytesPosition> {
165    if ranges.len() < 2 {
166      ranges
167    } else {
168      ranges.sort_by(|a, b| {
169        let a_start = a.get_start().unwrap_or(0);
170        let b_start = b.get_start().unwrap_or(0);
171        let start_ord = a_start.cmp(&b_start);
172        if start_ord == Ordering::Equal {
173          let a_end = a.get_end().unwrap_or(u64::MAX);
174          let b_end = b.get_end().unwrap_or(u64::MAX);
175          b_end.cmp(&a_end)
176        } else {
177          start_ord
178        }
179      });
180
181      let mut optimized_ranges = Vec::with_capacity(ranges.len());
182
183      let mut current_range = ranges[0].clone();
184
185      for range in ranges.iter().skip(1) {
186        if current_range.overlaps(range) {
187          current_range.merge_with(range);
188        } else {
189          optimized_ranges.push(current_range);
190          current_range = range.clone();
191        }
192      }
193
194      optimized_ranges.push(current_range);
195
196      optimized_ranges
197    }
198  }
199}
200
201#[derive(Debug, Clone)]
202pub struct GetOptions<'a> {
203  pub(crate) range: BytesPosition,
204  pub(crate) request_headers: &'a HeaderMap,
205}
206
207impl<'a> GetOptions<'a> {
208  pub fn new(range: BytesPosition, request_headers: &'a HeaderMap) -> Self {
209    Self {
210      range,
211      request_headers,
212    }
213  }
214
215  pub fn new_with_default_range(request_headers: &'a HeaderMap) -> Self {
216    Self::new(Default::default(), request_headers)
217  }
218
219  pub fn with_max_length(mut self, max_length: u64) -> Self {
220    self.range = BytesPosition::default().with_start(0).with_end(max_length);
221    self
222  }
223
224  pub fn with_range(mut self, range: BytesPosition) -> Self {
225    self.range = range;
226    self
227  }
228
229  /// Get the range.
230  pub fn range(&self) -> &BytesPosition {
231    &self.range
232  }
233
234  /// Get the request headers.
235  pub fn request_headers(&self) -> &'a HeaderMap {
236    self.request_headers
237  }
238}
239
240#[derive(Debug, Clone)]
241pub struct BytesPositionOptions<'a> {
242  pub(crate) positions: Vec<BytesPosition>,
243  pub(crate) headers: &'a HeaderMap,
244}
245
246impl<'a> BytesPositionOptions<'a> {
247  pub fn new(positions: Vec<BytesPosition>, headers: &'a HeaderMap) -> Self {
248    Self { positions, headers }
249  }
250
251  /// Get the response headers.
252  pub fn headers(&self) -> &'a HeaderMap {
253    self.headers
254  }
255
256  pub fn positions(&self) -> &Vec<BytesPosition> {
257    &self.positions
258  }
259
260  /// Get the inner value.
261  pub fn into_inner(self) -> Vec<BytesPosition> {
262    self.positions
263  }
264
265  /// Merge all bytes positions
266  pub fn merge_all(mut self) -> Self {
267    self.positions = BytesPosition::merge_all(self.positions);
268    self
269  }
270}
271
272#[derive(Debug, Clone)]
273pub struct RangeUrlOptions<'a> {
274  range: BytesPosition,
275  response_headers: &'a HeaderMap,
276}
277
278impl<'a> RangeUrlOptions<'a> {
279  pub fn new(range: BytesPosition, response_headers: &'a HeaderMap) -> Self {
280    Self {
281      range,
282      response_headers,
283    }
284  }
285
286  pub fn new_with_default_range(request_headers: &'a HeaderMap) -> Self {
287    Self::new(Default::default(), request_headers)
288  }
289
290  pub fn with_range(mut self, range: BytesPosition) -> Self {
291    self.range = range;
292    self
293  }
294
295  pub fn apply(self, url: Url) -> Url {
296    let range: String = String::from(&BytesRange::from(self.range()));
297
298    let url = if range.is_empty() {
299      url
300    } else {
301      url.add_headers(Headers::default().with_header("Range", range))
302    };
303
304    url.set_class(self.range().class)
305  }
306
307  /// Get the range.
308  pub fn range(&self) -> &BytesPosition {
309    &self.range
310  }
311
312  /// Get the response headers.
313  pub fn response_headers(&self) -> &'a HeaderMap {
314    self.response_headers
315  }
316}
317
318/// A struct to represent options passed to a `Storage` head call.
319#[derive(Debug, Clone)]
320pub struct HeadOptions<'a> {
321  request_headers: &'a HeaderMap,
322}
323
324impl<'a> HeadOptions<'a> {
325  /// Create a new HeadOptions struct.
326  pub fn new(request_headers: &'a HeaderMap) -> Self {
327    Self { request_headers }
328  }
329
330  /// Get the request headers.
331  pub fn request_headers(&self) -> &'a HeaderMap {
332    self.request_headers
333  }
334}
335
336impl<'a> From<&'a GetOptions<'a>> for HeadOptions<'a> {
337  fn from(options: &'a GetOptions<'a>) -> Self {
338    Self::new(options.request_headers())
339  }
340}
341
342#[cfg(test)]
343mod tests {
344  use std::collections::HashMap;
345
346  use super::*;
347
348  #[test]
349  fn bytes_range_overlapping_and_merge() {
350    let test_cases = vec![
351      (
352        BytesPosition::new(None, Some(2), None),
353        BytesPosition::new(Some(3), Some(5), None),
354        None,
355      ),
356      (
357        BytesPosition::new(None, Some(2), None),
358        BytesPosition::new(Some(3), None, None),
359        None,
360      ),
361      (
362        BytesPosition::new(None, Some(2), None),
363        BytesPosition::new(Some(2), Some(4), None),
364        Some(BytesPosition::new(None, Some(4), None)),
365      ),
366      (
367        BytesPosition::new(None, Some(2), None),
368        BytesPosition::new(Some(2), None, None),
369        Some(BytesPosition::new(None, None, None)),
370      ),
371      (
372        BytesPosition::new(None, Some(2), None),
373        BytesPosition::new(Some(1), Some(3), None),
374        Some(BytesPosition::new(None, Some(3), None)),
375      ),
376      (
377        BytesPosition::new(None, Some(2), None),
378        BytesPosition::new(Some(1), None, None),
379        Some(BytesPosition::new(None, None, None)),
380      ),
381      (
382        BytesPosition::new(None, Some(2), None),
383        BytesPosition::new(Some(0), Some(2), None),
384        Some(BytesPosition::new(None, Some(2), None)),
385      ),
386      (
387        BytesPosition::new(None, Some(2), None),
388        BytesPosition::new(None, Some(2), None),
389        Some(BytesPosition::new(None, Some(2), None)),
390      ),
391      (
392        BytesPosition::new(None, Some(2), None),
393        BytesPosition::new(Some(0), Some(1), None),
394        Some(BytesPosition::new(None, Some(2), None)),
395      ),
396      (
397        BytesPosition::new(None, Some(2), None),
398        BytesPosition::new(None, Some(1), None),
399        Some(BytesPosition::new(None, Some(2), None)),
400      ),
401      (
402        BytesPosition::new(None, Some(2), None),
403        BytesPosition::new(None, None, None),
404        Some(BytesPosition::new(None, None, None)),
405      ),
406      (
407        BytesPosition::new(Some(2), Some(4), None),
408        BytesPosition::new(Some(6), Some(8), None),
409        None,
410      ),
411      (
412        BytesPosition::new(Some(2), Some(4), None),
413        BytesPosition::new(Some(6), None, None),
414        None,
415      ),
416      (
417        BytesPosition::new(Some(2), Some(4), None),
418        BytesPosition::new(Some(4), Some(6), None),
419        Some(BytesPosition::new(Some(2), Some(6), None)),
420      ),
421      (
422        BytesPosition::new(Some(2), Some(4), None),
423        BytesPosition::new(Some(4), None, None),
424        Some(BytesPosition::new(Some(2), None, None)),
425      ),
426      (
427        BytesPosition::new(Some(2), Some(4), None),
428        BytesPosition::new(Some(3), Some(5), None),
429        Some(BytesPosition::new(Some(2), Some(5), None)),
430      ),
431      (
432        BytesPosition::new(Some(2), Some(4), None),
433        BytesPosition::new(Some(3), None, None),
434        Some(BytesPosition::new(Some(2), None, None)),
435      ),
436      (
437        BytesPosition::new(Some(2), Some(4), None),
438        BytesPosition::new(Some(2), Some(3), None),
439        Some(BytesPosition::new(Some(2), Some(4), None)),
440      ),
441      (
442        BytesPosition::new(Some(2), Some(4), None),
443        BytesPosition::new(None, Some(3), None),
444        Some(BytesPosition::new(None, Some(4), None)),
445      ),
446      (
447        BytesPosition::new(Some(2), Some(4), None),
448        BytesPosition::new(Some(1), Some(3), None),
449        Some(BytesPosition::new(Some(1), Some(4), None)),
450      ),
451      (
452        BytesPosition::new(Some(2), Some(4), None),
453        BytesPosition::new(None, Some(3), None),
454        Some(BytesPosition::new(None, Some(4), None)),
455      ),
456      (
457        BytesPosition::new(Some(2), Some(4), None),
458        BytesPosition::new(Some(0), Some(2), None),
459        Some(BytesPosition::new(Some(0), Some(4), None)),
460      ),
461      (
462        BytesPosition::new(Some(2), Some(4), None),
463        BytesPosition::new(None, Some(2), None),
464        Some(BytesPosition::new(None, Some(4), None)),
465      ),
466      (
467        BytesPosition::new(Some(2), Some(4), None),
468        BytesPosition::new(Some(0), Some(1), None),
469        None,
470      ),
471      (
472        BytesPosition::new(Some(2), Some(4), None),
473        BytesPosition::new(None, Some(1), None),
474        None,
475      ),
476      (
477        BytesPosition::new(Some(2), Some(4), None),
478        BytesPosition::new(None, None, None),
479        Some(BytesPosition::new(None, None, None)),
480      ),
481      (
482        BytesPosition::new(Some(2), None, None),
483        BytesPosition::new(Some(4), Some(6), None),
484        Some(BytesPosition::new(Some(2), None, None)),
485      ),
486      (
487        BytesPosition::new(Some(2), None, None),
488        BytesPosition::new(Some(4), None, None),
489        Some(BytesPosition::new(Some(2), None, None)),
490      ),
491      (
492        BytesPosition::new(Some(2), None, None),
493        BytesPosition::new(Some(2), Some(4), None),
494        Some(BytesPosition::new(Some(2), None, None)),
495      ),
496      (
497        BytesPosition::new(Some(2), None, None),
498        BytesPosition::new(Some(2), None, None),
499        Some(BytesPosition::new(Some(2), None, None)),
500      ),
501      (
502        BytesPosition::new(Some(2), None, None),
503        BytesPosition::new(Some(1), Some(3), None),
504        Some(BytesPosition::new(Some(1), None, None)),
505      ),
506      (
507        BytesPosition::new(Some(2), None, None),
508        BytesPosition::new(None, Some(3), None),
509        Some(BytesPosition::new(None, None, None)),
510      ),
511      (
512        BytesPosition::new(Some(2), None, None),
513        BytesPosition::new(Some(0), Some(2), None),
514        Some(BytesPosition::new(Some(0), None, None)),
515      ),
516      (
517        BytesPosition::new(Some(2), None, None),
518        BytesPosition::new(None, Some(2), None),
519        Some(BytesPosition::new(None, None, None)),
520      ),
521      (
522        BytesPosition::new(Some(2), None, None),
523        BytesPosition::new(Some(0), Some(1), None),
524        None,
525      ),
526      (
527        BytesPosition::new(Some(2), None, None),
528        BytesPosition::new(None, Some(1), None),
529        None,
530      ),
531      (
532        BytesPosition::new(Some(2), None, None),
533        BytesPosition::new(None, None, None),
534        Some(BytesPosition::new(None, None, None)),
535      ),
536      (
537        BytesPosition::new(None, None, None),
538        BytesPosition::new(None, None, None),
539        Some(BytesPosition::new(None, None, None)),
540      ),
541    ];
542
543    for (index, (a, b, expected)) in test_cases.iter().enumerate() {
544      println!("Test case {index}");
545      println!("  {a:?}");
546      println!("  {b:?}");
547      println!("  {expected:?}");
548
549      if a.overlaps(b) {
550        assert_eq!(*a.clone().merge_with(b), expected.clone().unwrap());
551      } else {
552        assert!(expected.is_none())
553      }
554    }
555  }
556
557  #[test]
558  fn bytes_range_merge_all_when_list_is_empty() {
559    assert_eq!(BytesPosition::merge_all(Vec::new()), Vec::new());
560  }
561
562  #[test]
563  fn bytes_range_merge_all_when_list_has_one_range() {
564    assert_eq!(
565      BytesPosition::merge_all(vec![BytesPosition::default()]),
566      vec![BytesPosition::default()]
567    );
568  }
569
570  #[test]
571  fn bytes_position_merge_class_header() {
572    assert_eq!(
573      BytesPosition::merge_all(vec![
574        BytesPosition::new(None, Some(1), Some(Class::Header)),
575        BytesPosition::new(None, Some(2), Some(Class::Header))
576      ]),
577      vec![BytesPosition::new(None, Some(2), Some(Class::Header))]
578    );
579  }
580
581  #[test]
582  fn bytes_position_merge_class_body() {
583    assert_eq!(
584      BytesPosition::merge_all(vec![
585        BytesPosition::new(None, Some(1), Some(Class::Body)),
586        BytesPosition::new(None, Some(3), Some(Class::Body))
587      ]),
588      vec![BytesPosition::new(None, Some(3), Some(Class::Body))]
589    );
590  }
591
592  #[test]
593  fn bytes_position_merge_class_none() {
594    assert_eq!(
595      BytesPosition::merge_all(vec![
596        BytesPosition::new(Some(1), Some(2), None),
597        BytesPosition::new(Some(2), Some(3), None)
598      ]),
599      vec![BytesPosition::new(Some(1), Some(3), None)]
600    );
601  }
602
603  #[test]
604  fn bytes_position_merge_class_different() {
605    assert_eq!(
606      BytesPosition::merge_all(vec![
607        BytesPosition::new(Some(1), Some(2), Some(Class::Header)),
608        BytesPosition::new(Some(2), Some(3), Some(Class::Body))
609      ]),
610      vec![BytesPosition::new(Some(1), Some(3), None)]
611    );
612  }
613
614  #[test]
615  fn bytes_range_merge_all_when_list_has_many_ranges() {
616    let ranges = vec![
617      BytesPosition::new(None, Some(1), None),
618      BytesPosition::new(Some(1), Some(2), None),
619      BytesPosition::new(Some(5), Some(6), None),
620      BytesPosition::new(Some(5), Some(8), None),
621      BytesPosition::new(Some(6), Some(7), None),
622      BytesPosition::new(Some(4), Some(5), None),
623      BytesPosition::new(Some(3), Some(6), None),
624      BytesPosition::new(Some(10), Some(12), None),
625      BytesPosition::new(Some(10), Some(12), None),
626      BytesPosition::new(Some(10), Some(14), None),
627      BytesPosition::new(Some(14), Some(15), None),
628      BytesPosition::new(Some(12), Some(16), None),
629      BytesPosition::new(Some(17), Some(19), None),
630      BytesPosition::new(Some(21), Some(23), None),
631      BytesPosition::new(Some(18), Some(22), None),
632      BytesPosition::new(Some(24), None, None),
633      BytesPosition::new(Some(24), Some(30), None),
634      BytesPosition::new(Some(31), Some(33), None),
635      BytesPosition::new(Some(35), None, None),
636    ];
637
638    let expected_ranges = vec![
639      BytesPosition::new(None, Some(2), None),
640      BytesPosition::new(Some(3), Some(8), None),
641      BytesPosition::new(Some(10), Some(16), None),
642      BytesPosition::new(Some(17), Some(23), None),
643      BytesPosition::new(Some(24), None, None),
644    ];
645
646    assert_eq!(BytesPosition::merge_all(ranges), expected_ranges);
647  }
648
649  #[test]
650  fn bytes_position_new() {
651    let result = BytesPosition::new(Some(1), Some(2), Some(Class::Header));
652    assert_eq!(result.start, Some(1));
653    assert_eq!(result.end, Some(2));
654    assert_eq!(result.class, Some(Class::Header));
655  }
656
657  #[test]
658  fn bytes_position_with_start() {
659    let result = BytesPosition::default().with_start(1);
660    assert_eq!(result.start, Some(1));
661  }
662
663  #[test]
664  fn bytes_position_with_end() {
665    let result = BytesPosition::default().with_end(1);
666    assert_eq!(result.end, Some(1));
667  }
668
669  #[test]
670  fn bytes_position_with_class() {
671    let result = BytesPosition::default().with_class(Class::Header);
672    assert_eq!(result.class, Some(Class::Header));
673  }
674
675  #[test]
676  fn bytes_position_set_class() {
677    let result = BytesPosition::default().set_class(Some(Class::Header));
678    assert_eq!(result.class, Some(Class::Header));
679  }
680
681  #[test]
682  fn data_block_update_classes_all_some() {
683    let blocks = DataBlock::update_classes(vec![
684      DataBlock::Range(BytesPosition::new(None, Some(1), Some(Class::Body))),
685      DataBlock::Data(vec![], Some(Class::Header)),
686    ]);
687    for block in blocks {
688      let class = match block {
689        DataBlock::Range(pos) => pos.class,
690        DataBlock::Data(_, class) => class,
691      };
692      assert!(class.is_some());
693    }
694  }
695
696  #[test]
697  fn data_block_update_classes_one_none() {
698    let blocks = DataBlock::update_classes(vec![
699      DataBlock::Range(BytesPosition::new(None, Some(1), Some(Class::Body))),
700      DataBlock::Data(vec![], None),
701    ]);
702    for block in blocks {
703      let class = match block {
704        DataBlock::Range(pos) => pos.class,
705        DataBlock::Data(_, class) => class,
706      };
707      assert!(class.is_none());
708    }
709  }
710
711  #[test]
712  fn data_block_from_bytes_positions() {
713    let blocks = DataBlock::from_bytes_positions(vec![
714      BytesPosition::new(None, Some(1), None),
715      BytesPosition::new(Some(1), Some(2), None),
716    ]);
717    assert_eq!(
718      blocks,
719      vec![DataBlock::Range(BytesPosition::new(None, Some(2), None))]
720    );
721  }
722
723  #[test]
724  fn byte_range_from_byte_position() {
725    let result: BytesRange = BytesRange::from(&BytesPosition::default().with_start(5).with_end(10));
726    let expected = BytesRange::new(Some(5), Some(9));
727    assert_eq!(result, expected);
728  }
729
730  #[test]
731  fn get_options_with_max_length() {
732    let request_headers = Default::default();
733    let result = GetOptions::new_with_default_range(&request_headers).with_max_length(1);
734    assert_eq!(
735      result.range(),
736      &BytesPosition::default().with_start(0).with_end(1)
737    );
738  }
739
740  #[test]
741  fn get_options_with_range() {
742    let request_headers = Default::default();
743    let result = GetOptions::new_with_default_range(&request_headers)
744      .with_range(BytesPosition::new(Some(5), Some(11), Some(Class::Header)));
745    assert_eq!(
746      result.range(),
747      &BytesPosition::new(Some(5), Some(11), Some(Class::Header))
748    );
749  }
750
751  #[test]
752  fn url_options_with_range() {
753    let request_headers = Default::default();
754    let result = RangeUrlOptions::new_with_default_range(&request_headers)
755      .with_range(BytesPosition::new(Some(5), Some(11), Some(Class::Header)));
756    assert_eq!(
757      result.range(),
758      &BytesPosition::new(Some(5), Some(11), Some(Class::Header))
759    );
760  }
761
762  #[test]
763  fn url_options_apply_with_bytes_range() {
764    let result = RangeUrlOptions::new(
765      BytesPosition::new(Some(5), Some(11), Some(Class::Header)),
766      &Default::default(),
767    )
768    .apply(Url::new(""));
769    println!("{result:?}");
770    assert_eq!(
771      result,
772      Url::new("")
773        .with_headers(Headers::new(HashMap::new()).with_header("Range", "bytes=5-10"))
774        .with_class(Class::Header)
775    );
776  }
777
778  #[test]
779  fn url_options_apply_no_bytes_range() {
780    let result = RangeUrlOptions::new_with_default_range(&Default::default()).apply(Url::new(""));
781    assert_eq!(result, Url::new(""));
782  }
783
784  #[test]
785  fn url_options_apply_with_headers() {
786    let result = RangeUrlOptions::new(
787      BytesPosition::new(Some(5), Some(11), Some(Class::Header)),
788      &Default::default(),
789    )
790    .apply(Url::new("").with_headers(Headers::default().with_header("header", "value")));
791    println!("{result:?}");
792
793    assert_eq!(
794      result,
795      Url::new("")
796        .with_headers(
797          Headers::new(HashMap::new())
798            .with_header("Range", "bytes=5-10")
799            .with_header("header", "value")
800        )
801        .with_class(Class::Header)
802    );
803  }
804}