Skip to main content

bio_seq/seq/
slice.rs

1// Copyright 2021-2024 Jeff Knaggs
2// Licensed under the MIT license (http://opensource.org/licenses/MIT)
3// This file may not be copied, modified, or distributed
4// except according to those terms.
5
6use crate::codec::Codec;
7use crate::error::ParseBioError;
8use crate::seq::Seq;
9use crate::{
10    Complement, ComplementMut, Reverse, ReverseComplement, ReverseComplementMut, ReverseMut,
11};
12
13use crate::Bs;
14use bitvec::field::BitField;
15
16use core::fmt;
17use core::hash::{Hash, Hasher};
18use core::marker::PhantomData;
19use core::str;
20
21use core::ops::{BitAnd, BitOr};
22
23/// An unsized, read-only window into part of a sequence
24#[derive(Debug, Eq)]
25#[repr(transparent)]
26pub struct SeqSlice<A: Codec> {
27    pub(crate) _p: PhantomData<A>,
28    pub(crate) bs: Bs,
29}
30
31impl<A: Codec> TryFrom<&SeqSlice<A>> for usize {
32    type Error = ParseBioError;
33
34    fn try_from(slice: &SeqSlice<A>) -> Result<usize, Self::Error> {
35        if slice.bs.is_empty() {
36            Ok(0)
37        } else if slice.bs.len() <= usize::BITS as usize {
38            Ok(slice.bs.load_le::<usize>())
39        } else {
40            let len: usize = slice.bs.len() / A::BITS as usize;
41            let maximum: usize = usize::BITS as usize / A::BITS as usize;
42            Err(ParseBioError::SequenceTooLong(maximum, len))
43        }
44    }
45}
46
47impl<A: Codec> From<&SeqSlice<A>> for u8 {
48    fn from(slice: &SeqSlice<A>) -> u8 {
49        debug_assert!(slice.bs.len() <= u8::BITS as usize);
50        if slice.bs.is_empty() {
51            0
52        } else {
53            slice.bs.load_le::<u8>()
54        }
55    }
56}
57
58impl<A: Codec> SeqSlice<A> {
59    /// unsafely index into the `i`th position of a sequence
60    #[must_use]
61    pub fn nth(&self, i: usize) -> A {
62        A::unsafe_from_bits(self[i].into())
63    }
64
65    #[must_use]
66    pub fn len(&self) -> usize {
67        self.bs.len() / A::BITS as usize
68    }
69
70    /// Get the `i`th element of a `Seq`. Returns `None` if index out of range.
71    #[must_use]
72    pub fn get(&self, i: usize) -> Option<A> {
73        if i >= self.bs.len() / A::BITS as usize {
74            None
75        } else {
76            Some(A::unsafe_from_bits(self[i].into()))
77        }
78    }
79
80    #[must_use]
81    pub fn is_empty(&self) -> bool {
82        self.len() == 0
83    }
84}
85
86impl<A: Codec> From<&SeqSlice<A>> for String {
87    fn from(seq: &SeqSlice<A>) -> Self {
88        seq.into_iter().map(Codec::to_char).collect()
89    }
90}
91
92impl<A: Codec> PartialEq<SeqSlice<A>> for SeqSlice<A> {
93    fn eq(&self, other: &SeqSlice<A>) -> bool {
94        self.bs == other.bs
95    }
96}
97
98impl<A: Codec> PartialEq<SeqSlice<A>> for &SeqSlice<A> {
99    fn eq(&self, other: &SeqSlice<A>) -> bool {
100        self.bs == other.bs
101    }
102}
103
104impl<A: Codec> PartialEq<Seq<A>> for SeqSlice<A> {
105    fn eq(&self, other: &Seq<A>) -> bool {
106        self == other.as_ref()
107    }
108}
109
110impl<A: Codec> PartialEq<Seq<A>> for &SeqSlice<A> {
111    fn eq(&self, other: &Seq<A>) -> bool {
112        *self == other.as_ref()
113    }
114}
115
116impl<A: Codec> PartialEq<&str> for SeqSlice<A> {
117    fn eq(&self, other: &&str) -> bool {
118        let bs = other.as_bytes();
119        if bs.len() != self.len() {
120            return false;
121        }
122        for (a, c) in self.iter().zip(bs) {
123            match A::try_from_ascii(*c) {
124                Some(b) => {
125                    if a != b {
126                        return false;
127                    }
128                }
129                None => return false,
130            }
131        }
132        true
133    }
134}
135
136impl<A: Codec> Hash for SeqSlice<A> {
137    fn hash<H: Hasher>(&self, state: &mut H) {
138        // Prefix with length as 8 little-endian bytes so the byte stream is
139        // identical on 32-/64-bit targets and across endianness. Going through
140        // `u64::hash` would route via `Hasher::write_u64`, whose default impl
141        // emits native-endian bytes.
142        state.write(&(self.len() as u64).to_le_bytes());
143        crate::hash::hash_bits(&self.bs, state);
144    }
145}
146
147/// Clone a borrowed slice of a sequence into an owned version.
148///
149/// ```
150/// use bio_seq::prelude::*;
151///
152/// let seq = dna!("CATCGATCGATCG");
153/// let slice = &seq[2..7]; // TCGAT
154/// let owned = slice.to_owned();
155///
156/// assert_eq!(&owned, &seq[2..7]);
157/// ```
158///
159impl<A: Codec> ToOwned for SeqSlice<A> {
160    type Owned = Seq<A>;
161
162    fn to_owned(&self) -> Self::Owned {
163        Seq {
164            _p: PhantomData,
165            bv: self.bs.into(),
166        }
167    }
168}
169
170impl<A: Codec> AsRef<SeqSlice<A>> for SeqSlice<A> {
171    fn as_ref(&self) -> &SeqSlice<A> {
172        self
173    }
174}
175
176impl<A: Codec> fmt::Display for SeqSlice<A> {
177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178        for symbol in self {
179            write!(f, "{}", symbol.to_char())?;
180        }
181        Ok(())
182    }
183}
184
185impl<A: Codec> BitAnd for &SeqSlice<A> {
186    type Output = Seq<A>;
187
188    fn bitand(self, rhs: Self) -> Self::Output {
189        let mut bv = self.bs.to_bitvec();
190        bv &= &rhs.bs;
191        Seq::<A> {
192            bv,
193            _p: PhantomData,
194        }
195    }
196}
197
198impl<A: Codec> BitOr for &SeqSlice<A> {
199    type Output = Seq<A>;
200
201    fn bitor(self, rhs: Self) -> Self::Output {
202        let mut bv = self.bs.to_bitvec();
203        bv |= &rhs.bs;
204
205        Seq::<A> {
206            bv,
207            _p: PhantomData,
208        }
209    }
210}
211
212impl<A: Codec> ReverseMut for SeqSlice<A> {
213    fn rev(&mut self) {
214        self.bs.reverse();
215        for chunk in self.bs.rchunks_exact_mut(A::BITS as usize) {
216            chunk.reverse();
217        }
218    }
219}
220
221impl<A: Codec + ComplementMut> ComplementMut for SeqSlice<A> {
222    fn comp(&mut self) {
223        unsafe {
224            for base in self.bs.chunks_exact_mut(A::BITS as usize).remove_alias() {
225                let mut bc = A::unsafe_from_bits(base.load_le::<u8>());
226                bc.comp();
227                base.store(bc.to_bits() as usize);
228            }
229        }
230    }
231}
232
233impl<A: Codec + ComplementMut> ReverseComplementMut for SeqSlice<A> where
234    SeqSlice<A>: ComplementMut + ReverseMut
235{
236}
237
238impl<A: Codec> Reverse for SeqSlice<A> {}
239
240impl<A: Codec + ComplementMut> Complement for SeqSlice<A> {}
241
242impl<A: Codec + ComplementMut> ReverseComplement for SeqSlice<A> where
243    SeqSlice<A>: ComplementMut + ReverseMut
244{
245}