bedrs/traits/interval/coordinates.rs
1use crate::{
2 traits::{ChromBounds, ValueBounds},
3 Intersect, Overlap, Strand, Subtract,
4};
5use std::cmp::Ordering;
6
7use super::{
8 overlap::{StrandedOverlap, UnstrandedOverlap},
9 Distance, Segment,
10};
11
12/// The main trait representing an interval.
13///
14/// This trait can be derived on arbitrary structs that have
15/// the fields {chr, start, end} and those fields meet the
16/// minimum required bounds of `ChromBounds` and `ValueBounds`.
17///
18/// # Examples
19/// ```
20/// use bedrs::prelude::*;
21/// use bedrs_derive::Coordinates;
22///
23/// #[derive(Default, Coordinates)]
24/// struct MyInterval {
25/// chr: usize,
26/// start: usize,
27/// end: usize,
28/// }
29///
30/// let a = MyInterval { chr: 1, start: 10, end: 20};
31/// assert_eq!(a.chr(), &1);
32/// assert_eq!(a.start(), 10);
33/// assert_eq!(a.end(), 20);
34/// assert_eq!(a.strand(), None);
35///
36/// #[derive(Default, Coordinates)]
37/// struct MyStrandedInterval {
38/// chr: usize,
39/// start: usize,
40/// end: usize,
41/// strand: Strand,
42/// }
43///
44/// let a = MyStrandedInterval{
45/// chr: 1,
46/// start: 10,
47/// end: 20,
48/// strand: Strand::Reverse
49/// };
50/// assert_eq!(a.chr(), &1);
51/// assert_eq!(a.start(), 10);
52/// assert_eq!(a.end(), 20);
53/// assert_eq!(a.strand(), Some(Strand::Reverse));
54/// ```
55#[allow(clippy::len_without_is_empty)]
56pub trait Coordinates<C, T>
57where
58 C: ChromBounds,
59 T: ValueBounds,
60{
61 /// Returns the start coordinate of the interval.
62 ///
63 /// # Examples
64 /// ```
65 /// use bedrs::{Coordinates, Bed3};
66 ///
67 /// let iv = Bed3::new(1, 10, 20);
68 /// assert_eq!(iv.start(), 10);
69 /// ```
70 fn start(&self) -> T;
71
72 /// Returns the end coordinate of the interval.
73 ///
74 /// # Examples
75 /// ```
76 /// use bedrs::{Coordinates, Bed3};
77 ///
78 /// let iv = Bed3::new(1, 10, 20);
79 /// assert_eq!(iv.end(), 20);
80 /// ```
81 fn end(&self) -> T;
82
83 /// Returns a reference to the chromosome of the interval.
84 ///
85 /// *Note*: A reference is returned in the case that the chromosome
86 /// is a large type, such as a `String` or `Vec<u8>`.
87 ///
88 /// # Examples
89 /// ```
90 /// use bedrs::{Coordinates, Bed3};
91 ///
92 /// let iv = Bed3::new(1, 10, 20);
93 /// assert_eq!(iv.chr(), &1);
94 /// ```
95 fn chr(&self) -> &C;
96
97 /// Return the strand of the interval, if it has one.
98 ///
99 /// This is a default implementation that returns `None` for
100 /// intervals that do not have a strand.
101 ///
102 /// # Examples
103 ///
104 /// ```
105 /// use bedrs::{Coordinates, Bed3, Strand, StrandedBed3};
106 ///
107 /// let iv = Bed3::new(1, 10, 20);
108 /// assert_eq!(iv.strand(), None);
109 ///
110 /// let siv = StrandedBed3::new(1, 10, 20, Strand::Forward);
111 /// assert_eq!(siv.strand(), Some(Strand::Forward));
112 /// ```
113 fn strand(&self) -> Option<Strand> {
114 None
115 }
116
117 /// Update the start coordinate of the interval.
118 ///
119 ///
120 /// # Examples
121 ///
122 /// ```
123 /// use bedrs::{Coordinates, Bed3};
124 ///
125 /// let mut iv = Bed3::new(1, 10, 20);
126 /// assert_eq!(iv.start(), 10);
127 ///
128 /// iv.update_start(&5);
129 /// assert_eq!(iv.start(), 5);
130 /// ```
131 fn update_start(&mut self, val: &T);
132
133 /// Update the end coordinate of the interval.
134 ///
135 /// # Examples
136 ///
137 /// ```
138 /// use bedrs::{Coordinates, Bed3};
139 ///
140 /// let mut iv = Bed3::new(1, 10, 20);
141 /// assert_eq!(iv.end(), 20);
142 ///
143 /// iv.update_end(&30);
144 /// assert_eq!(iv.end(), 30);
145 /// ```
146 fn update_end(&mut self, val: &T);
147
148 /// Update the chromosome of the interval.
149 ///
150 /// # Examples
151 ///
152 /// ```
153 /// use bedrs::{Coordinates, Bed3};
154 ///
155 /// let mut iv = Bed3::new(1, 10, 20);
156 /// assert_eq!(iv.chr(), &1);
157 ///
158 /// iv.update_chr(&2);
159 /// assert_eq!(iv.chr(), &2);
160 /// ```
161 fn update_chr(&mut self, val: &C);
162
163 /// Update the strand of the interval.
164 ///
165 /// # Examples
166 /// ```
167 /// use bedrs::{Coordinates, StrandedBed3, Strand};
168 ///
169 /// let mut siv = StrandedBed3::new(1, 10, 20, Strand::Forward);
170 /// assert_eq!(siv.strand(), Some(Strand::Forward));
171 ///
172 /// siv.update_strand(Some(Strand::Reverse));
173 /// assert_eq!(siv.strand(), Some(Strand::Reverse));
174 /// ```
175 fn update_strand(&mut self, _strand: Option<Strand>) {
176 // Do nothing by default
177 }
178
179 /// Create a new interval with the same coordinates as the current one.
180 ///
181 /// *Note*: This is less verbose when working with generic types.
182 /// In most cases it can be better to use the `copy` or `clone` methods.
183 ///
184 /// # Examples
185 ///
186 /// ```
187 /// use bedrs::{Coordinates, Bed3};
188 ///
189 /// let iv = Bed3::new(1, 10, 20);
190 /// let new_iv = <Bed3<usize, usize> as Coordinates<usize, usize>>::from(&iv);
191 ///
192 /// assert!(iv.eq(&new_iv));
193 /// ```
194 fn from<Iv: Coordinates<C, T>>(other: &Iv) -> Self;
195
196 /// Creates an empty interval.
197 fn empty() -> Self;
198
199 /// Calculates the length of the interval across its start and end coordinates.
200 ///
201 /// # Examples
202 ///
203 /// ```
204 /// use bedrs::{Coordinates, Bed3};
205 ///
206 /// let iv = Bed3::new(1, 10, 20);
207 /// assert_eq!(iv.len(), 10);
208 /// ```
209 fn len(&self) -> T {
210 self.end().sub(self.start())
211 }
212
213 /// Update all attributes of the interval.
214 ///
215 /// # Examples
216 /// ```
217 /// use bedrs::{Coordinates, Bed3};
218 ///
219 /// let mut iv = Bed3::new(1, 10, 20);
220 /// assert!(iv.eq(&Bed3::new(1, 10, 20)));
221 ///
222 /// iv.update_all(&2, &5, &10);
223 /// assert!(iv.eq(&Bed3::new(2, 5, 10)));
224 /// ```
225 fn update_all(&mut self, chr: &C, start: &T, end: &T) {
226 self.update_chr(chr);
227 self.update_endpoints(start, end);
228 }
229
230 /// Update the endpoints of the interval.
231 ///
232 /// # Examples
233 /// ```
234 /// use bedrs::{Coordinates, Bed3};
235 ///
236 /// let mut iv = Bed3::new(1, 10, 20);
237 /// assert!(iv.eq(&Bed3::new(1, 10, 20)));
238 ///
239 /// iv.update_endpoints(&5, &10);
240 /// assert!(iv.eq(&Bed3::new(1, 5, 10)));
241 /// ```
242 fn update_endpoints(&mut self, start: &T, end: &T) {
243 self.update_start(start);
244 self.update_end(end);
245 }
246
247 /// Update all the attributes of the interval from another interval.
248 ///
249 /// # Examples
250 /// ```
251 /// use bedrs::{Coordinates, Bed3};
252 ///
253 /// let mut iv = Bed3::new(1, 10, 20);
254 /// assert!(iv.eq(&Bed3::new(1, 10, 20)));
255 ///
256 /// iv.update_all_from(&Bed3::new(2, 5, 10));
257 /// assert!(iv.eq(&Bed3::new(2, 5, 10)));
258 /// ```
259 fn update_all_from<I: Coordinates<C, T>>(&mut self, other: &I) {
260 self.update_chr(other.chr());
261 self.update_endpoints(&other.start(), &other.end());
262 }
263
264 /// Update only the endpoints of the interval from another interval.
265 ///
266 /// # Examples
267 /// ```
268 /// use bedrs::{Coordinates, Bed3};
269 ///
270 /// let mut iv = Bed3::new(1, 10, 20);
271 /// assert!(iv.eq(&Bed3::new(1, 10, 20)));
272 ///
273 /// iv.update_endpoints_from(&Bed3::new(2, 5, 10));
274 /// assert!(iv.eq(&Bed3::new(1, 5, 10)));
275 /// ```
276 fn update_endpoints_from<I: Coordinates<C, T>>(&mut self, other: &I) {
277 self.update_start(&other.start());
278 self.update_end(&other.end());
279 }
280
281 /// Extend the interval to the left by a value.
282 /// This is equivalent to subtracting the value from the start coordinate.
283 ///
284 /// # Examples
285 /// ```
286 /// use bedrs::{Coordinates, Bed3};
287 ///
288 /// let mut iv = Bed3::new(1, 10, 20);
289 /// assert!(iv.eq(&Bed3::new(1, 10, 20)));
290 ///
291 /// iv.extend_left(&5);
292 /// assert!(iv.eq(&Bed3::new(1, 5, 20)));
293 /// ```
294 fn extend_left(&mut self, val: &T) {
295 if self.start().lt(val) {
296 self.update_start(&T::zero());
297 } else {
298 self.update_start(&self.start().sub(*val));
299 }
300 }
301
302 /// Extend the interval to the right by a value.
303 /// This is equivalent to adding the value to the end coordinate.
304 ///
305 /// If a maximum bound is provided, the new end coordinate will be capped
306 /// at that maximum value.
307 ///
308 /// # Examples
309 /// ```
310 /// use bedrs::{Coordinates, Bed3};
311 ///
312 /// let mut iv = Bed3::new(1, 10, 20);
313 /// assert!(iv.eq(&Bed3::new(1, 10, 20)));
314 ///
315 /// iv.extend_right(&5, None);
316 /// assert!(iv.eq(&Bed3::new(1, 10, 25)));
317 ///
318 /// iv.extend_right(&5, Some(27));
319 /// assert!(iv.eq(&Bed3::new(1, 10, 27)));
320 /// ```
321 fn extend_right(&mut self, val: &T, max_bound: Option<T>) {
322 let new_end = self.end().add(*val);
323 if let Some(max) = max_bound {
324 self.update_end(&new_end.min(max));
325 } else {
326 self.update_end(&new_end);
327 }
328 }
329
330 /// Extend the interval to the left and right by a value.
331 /// This is equivalent to subtracting the value from the start coordinate
332 /// and adding the value to the end coordinate.
333 ///
334 /// If a maximum bound is provided, the new end coordinate will be capped
335 /// at that maximum value.
336 ///
337 /// # Examples
338 /// ```
339 /// use bedrs::{Coordinates, Bed3};
340 ///
341 /// let mut iv = Bed3::new(1, 10, 20);
342 /// assert!(iv.eq(&Bed3::new(1, 10, 20)));
343 ///
344 /// iv.extend(&5, None);
345 /// assert!(iv.eq(&Bed3::new(1, 5, 25)));
346 ///
347 /// iv.extend(&5, Some(27));
348 /// assert!(iv.eq(&Bed3::new(1, 0, 27)));
349 /// ```
350 fn extend(&mut self, val: &T, max_bound: Option<T>) {
351 self.extend_left(val);
352 self.extend_right(val, max_bound);
353 }
354
355 /// Calculate the length of the interval as a fraction of the total length.
356 ///
357 /// # Examples
358 /// ```
359 /// use bedrs::{Coordinates, Bed3};
360 ///
361 /// let iv = Bed3::new(1, 10, 20);
362 /// assert_eq!(iv.f_len(0.5), 5);
363 /// assert_eq!(iv.f_len(0.3), 3);
364 /// assert_eq!(iv.f_len(2.0), 20);
365 /// ```
366 fn f_len(&self, frac: f64) -> T {
367 let len_f: f64 = self.len().to_f64().unwrap();
368 let n = len_f * frac;
369 T::from_f64(n.round()).unwrap()
370 }
371
372 /// Compare two intervals by their genomic coordinates.
373 ///
374 /// # Examples
375 /// ```
376 /// use bedrs::{Coordinates, Bed3};
377 ///
378 /// let a = Bed3::new(1, 10, 20);
379 /// let b = Bed3::new(1, 10, 20);
380 /// let c = Bed3::new(1, 20, 30);
381 /// let d = Bed3::new(2, 10, 20);
382 /// let e = Bed3::new(1, 5, 10);
383 ///
384 /// // a == b
385 /// assert_eq!(a.coord_cmp(&b), std::cmp::Ordering::Equal);
386 ///
387 /// // a < c
388 /// assert_eq!(a.coord_cmp(&c), std::cmp::Ordering::Less);
389 ///
390 /// // a < d
391 /// assert_eq!(a.coord_cmp(&d), std::cmp::Ordering::Less);
392 ///
393 /// // a > e
394 /// assert_eq!(a.coord_cmp(&e), std::cmp::Ordering::Greater);
395 /// ```
396 fn coord_cmp<I: Coordinates<C, T>>(&self, other: &I) -> Ordering {
397 match self.chr().cmp(other.chr()) {
398 Ordering::Equal => match self.start().cmp(&other.start()) {
399 Ordering::Equal => match self.end().cmp(&other.end()) {
400 Ordering::Equal => self.strand().cmp(&other.strand()),
401 order => order,
402 },
403 order => order,
404 },
405 order => order,
406 }
407 }
408 /// Compare two intervals, but bias the `other` interval to extend
409 /// further to the left by `bias` units.
410 ///
411 /// Used to find the lower bound of an interval in a sorted container
412 /// where the maximum range of the intervals is known a priori.
413 fn biased_coord_cmp<I: Coordinates<C, T>>(&self, other: &I, bias: T) -> Ordering {
414 match self.chr().cmp(other.chr()) {
415 Ordering::Equal => {
416 let comp = if other.start() < bias {
417 None // can't compare the intervals since they both bias below zero
418 } else {
419 Some(self.start().cmp(&other.start().sub(bias)))
420 };
421 if let Some(comp) = comp {
422 match comp {
423 Ordering::Equal => match self.end().cmp(&other.end()) {
424 Ordering::Equal => self.strand().cmp(&other.strand()),
425 order => order,
426 },
427 order => order,
428 }
429 } else {
430 Ordering::Equal
431 }
432 }
433 order => order,
434 }
435 }
436 fn biased_lt<I: Coordinates<C, T>>(&self, other: &I, bias: T) -> bool {
437 self.biased_coord_cmp(other, bias) == Ordering::Less
438 }
439 fn lt<I: Coordinates<C, T>>(&self, other: &I) -> bool {
440 self.coord_cmp(other) == Ordering::Less
441 }
442 fn gt<I: Coordinates<C, T>>(&self, other: &I) -> bool {
443 self.coord_cmp(other) == Ordering::Greater
444 }
445 fn eq<I: Coordinates<C, T>>(&self, other: &I) -> bool {
446 self.coord_cmp(other) == Ordering::Equal
447 }
448 fn pprint(&self) -> String {
449 format!(
450 "{:?}:{:?}-{:?}:{}",
451 self.chr(),
452 self.start(),
453 self.end(),
454 self.strand().unwrap_or(Strand::Unknown)
455 )
456 }
457}
458
459impl<I, C, T> Distance<C, T> for I
460where
461 I: Coordinates<C, T>,
462 C: ChromBounds,
463 T: ValueBounds,
464{
465}
466
467impl<I, C, T> Intersect<C, T> for I
468where
469 I: Coordinates<C, T>,
470 C: ChromBounds,
471 T: ValueBounds,
472{
473}
474
475impl<I, C, T> Overlap<C, T> for I
476where
477 I: Coordinates<C, T>,
478 C: ChromBounds,
479 T: ValueBounds,
480{
481}
482
483impl<I, C, T> StrandedOverlap<C, T> for I
484where
485 I: Coordinates<C, T>,
486 C: ChromBounds,
487 T: ValueBounds,
488{
489}
490
491impl<I, C, T> UnstrandedOverlap<C, T> for I
492where
493 I: Coordinates<C, T>,
494 C: ChromBounds,
495 T: ValueBounds,
496{
497}
498
499impl<I, C, T> Subtract<C, T> for I
500where
501 I: Coordinates<C, T>,
502 C: ChromBounds,
503 T: ValueBounds,
504{
505}
506
507impl<I, C, T> Segment<C, T> for I
508where
509 I: Coordinates<C, T>,
510 C: ChromBounds,
511 T: ValueBounds,
512{
513}
514
515#[cfg(test)]
516mod testing {
517 use crate::{traits::Coordinates, BaseInterval, Bed3};
518
519 // define a custom interval struct for testing
520 struct CustomInterval {
521 left: usize,
522 right: usize,
523 }
524 impl Coordinates<usize, usize> for CustomInterval {
525 fn empty() -> Self {
526 Self { left: 0, right: 0 }
527 }
528 fn start(&self) -> usize {
529 self.left
530 }
531 fn end(&self) -> usize {
532 self.right
533 }
534 fn chr(&self) -> &usize {
535 &0
536 }
537 fn update_start(&mut self, val: &usize) {
538 self.left = *val;
539 }
540 fn update_end(&mut self, val: &usize) {
541 self.right = *val;
542 }
543 #[allow(unused)]
544 fn update_chr(&mut self, val: &usize) {}
545 fn from<Iv: Coordinates<usize, usize>>(other: &Iv) -> Self {
546 Self {
547 left: other.start(),
548 right: other.end(),
549 }
550 }
551 }
552
553 // define a custom interval struct for testing
554 struct CustomIntervalMeta {
555 left: usize,
556 right: usize,
557 meta: String,
558 }
559 impl Coordinates<usize, usize> for CustomIntervalMeta {
560 fn empty() -> Self {
561 Self {
562 left: 0,
563 right: 0,
564 meta: String::new(),
565 }
566 }
567 fn start(&self) -> usize {
568 self.left
569 }
570 fn end(&self) -> usize {
571 self.right
572 }
573 fn chr(&self) -> &usize {
574 &0
575 }
576 fn update_start(&mut self, val: &usize) {
577 self.left = *val;
578 }
579 fn update_end(&mut self, val: &usize) {
580 self.right = *val;
581 }
582 #[allow(unused)]
583 fn update_chr(&mut self, val: &usize) {}
584 fn from<Iv: Coordinates<usize, usize>>(other: &Iv) -> Self {
585 Self {
586 left: other.start(),
587 right: other.end(),
588 meta: String::new(),
589 }
590 }
591 }
592
593 #[test]
594 fn test_custom_interval() {
595 let left = 10;
596 let right = 100;
597 let a = CustomInterval { left, right };
598 assert_eq!(a.start(), 10);
599 assert_eq!(a.end(), 100);
600 assert_eq!(*a.chr(), 0);
601
602 // for coverage
603 let mut a = CustomInterval::empty();
604 a.update_chr(&0);
605 //
606 }
607
608 #[test]
609 fn test_custom_interval_update() {
610 let mut a = CustomInterval {
611 left: 10,
612 right: 100,
613 };
614 assert_eq!(a.start(), 10);
615 assert_eq!(a.end(), 100);
616 a.update_start(&30);
617 a.update_end(&120);
618 assert_eq!(a.start(), 30);
619 assert_eq!(a.end(), 120);
620 }
621
622 #[test]
623 fn test_custom_interval_transcode() {
624 let a = CustomInterval {
625 left: 10,
626 right: 100,
627 };
628 let b: CustomInterval = Coordinates::from(&a);
629 assert_eq!(a.start(), b.start());
630 assert_eq!(a.end(), b.end());
631 assert_eq!(a.chr(), b.chr());
632 }
633 #[test]
634 fn test_custom_interval_with_meta() {
635 let left = 10;
636 let right = 100;
637 let meta = "some_meta".to_string();
638 let a = CustomIntervalMeta { left, right, meta };
639 assert_eq!(a.start(), 10);
640 assert_eq!(a.end(), 100);
641 assert_eq!(*a.chr(), 0);
642 }
643
644 #[test]
645 fn test_custom_interval_meta_update() {
646 let mut a = CustomIntervalMeta {
647 left: 10,
648 right: 100,
649 meta: String::from("hello"),
650 };
651 assert_eq!(a.start(), 10);
652 assert_eq!(a.end(), 100);
653 a.update_start(&30);
654 a.update_end(&120);
655 a.update_chr(&0);
656 assert_eq!(a.start(), 30);
657 assert_eq!(a.end(), 120);
658 let _a = CustomIntervalMeta::empty();
659 }
660
661 #[test]
662 fn test_custom_interval_meta_transcode() {
663 let a = CustomIntervalMeta {
664 left: 10,
665 right: 100,
666 meta: String::from("hello"),
667 };
668 let b: CustomIntervalMeta = Coordinates::from(&a);
669 assert_eq!(a.start(), b.start());
670 assert_eq!(a.end(), b.end());
671 assert_eq!(a.chr(), b.chr());
672 assert_ne!(a.meta, b.meta);
673 }
674
675 #[test]
676 fn test_convenience_methods() {
677 let a = BaseInterval::new(10, 20);
678 let b = BaseInterval::new(30, 50);
679 let c = BaseInterval::new(30, 50);
680 assert!(a.lt(&b));
681 assert!(b.gt(&a));
682 assert!(b.eq(&c));
683 }
684
685 #[test]
686 fn test_extend_left() {
687 let mut a = BaseInterval::new(10, 20);
688 let val = 5;
689 a.extend_left(&val);
690 assert_eq!(a.start(), 5);
691 assert_eq!(a.end(), 20);
692 }
693
694 #[test]
695 fn test_extend_left_bounded() {
696 let mut a = BaseInterval::new(10, 20);
697 let val = 11;
698 a.extend_left(&val);
699 assert_eq!(a.start(), 0);
700 assert_eq!(a.end(), 20);
701 }
702
703 #[test]
704 fn test_extend_right() {
705 let mut a = BaseInterval::new(10, 20);
706 let val = 5;
707 a.extend_right(&val, None);
708 assert_eq!(a.start(), 10);
709 assert_eq!(a.end(), 25);
710 }
711
712 #[test]
713 fn test_extend_right_bounded() {
714 let mut a = BaseInterval::new(10, 20);
715 let val = 5;
716 a.extend_right(&val, Some(22));
717 assert_eq!(a.start(), 10);
718 assert_eq!(a.end(), 22);
719 }
720
721 #[test]
722 fn test_extend_both() {
723 let mut a = BaseInterval::new(10, 20);
724 let val = 5;
725 a.extend(&val, None);
726 assert_eq!(a.start(), 5);
727 assert_eq!(a.end(), 25);
728 }
729
730 #[test]
731 fn test_extend_both_bounded() {
732 let mut a = BaseInterval::new(10, 20);
733 let val = 5;
734 a.extend(&val, Some(22));
735 assert_eq!(a.start(), 5);
736 assert_eq!(a.end(), 22);
737 }
738
739 #[test]
740 fn test_update_from() {
741 let mut a = Bed3::new(1, 10, 20);
742 let b = Bed3::new(2, 30, 50);
743 a.update_endpoints_from(&b);
744 assert_eq!(a.chr(), &1);
745 assert_eq!(a.start(), 30);
746 assert_eq!(a.end(), 50);
747 }
748}