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}