noodles_fasta/record/sequence.rs
1//! FASTA record sequence.
2
3pub mod complement;
4
5pub use self::complement::Complement;
6
7use std::ops::Index;
8
9use bytes::Bytes;
10use noodles_core::{position::SequenceIndex, region::Interval};
11
12/// A FASTA record sequence.
13#[derive(Clone, Debug, Default, Eq, PartialEq)]
14pub struct Sequence(Bytes);
15
16impl Sequence {
17 /// Returns the length of the sequence.
18 ///
19 /// # Examples
20 ///
21 /// ```
22 /// use noodles_fasta::record::Sequence;
23 /// let sequence = Sequence::default();
24 /// assert_eq!(sequence.len(), 0);
25 /// ```
26 pub fn len(&self) -> usize {
27 self.0.len()
28 }
29
30 /// Returns whether the sequence is empty.
31 ///
32 /// # Examples
33 ///
34 /// ```
35 /// use noodles_fasta::record::Sequence;
36 /// let sequence = Sequence::default();
37 /// assert!(sequence.is_empty());
38 /// ```
39 pub fn is_empty(&self) -> bool {
40 self.0.is_empty()
41 }
42
43 /// Returns a reference to a base at or slice of bases between the given index.
44 ///
45 /// # Examples
46 ///
47 /// ```
48 /// use noodles_core::Position;
49 /// use noodles_fasta::record::Sequence;
50 ///
51 /// let sequence = Sequence::from(b"ACGT".to_vec());
52 ///
53 /// let start = Position::try_from(2)?;
54 /// assert_eq!(sequence.get(start), Some(&b'C'));
55 ///
56 /// assert_eq!(sequence.get(start..), Some(&b"CGT"[..]));
57 ///
58 /// let end = Position::try_from(3)?;
59 /// assert_eq!(sequence.get(start..=end), Some(&b"CG"[..]));
60 /// # Ok::<_, noodles_core::position::TryFromIntError>(())
61 /// ```
62 pub fn get<I>(&self, index: I) -> Option<&I::Output>
63 where
64 I: SequenceIndex<u8>,
65 {
66 index.get(self.as_ref())
67 }
68
69 /// Returns a subset of the sequence within the given range.
70 ///
71 /// Unlike [`Self::get`], this returns the slice as a [`Sequence`].
72 ///
73 /// # Examples
74 ///
75 /// ```
76 /// use noodles_core::Position;
77 /// use noodles_fasta::record::Sequence;
78 ///
79 /// let sequence = Sequence::from(b"ACGT".to_vec());
80 ///
81 /// let start = Position::try_from(2)?;
82 /// let end = Position::try_from(3)?;
83 /// let actual = sequence.slice(start..=end);
84 ///
85 /// let expected = Sequence::from(b"CG".to_vec());
86 ///
87 /// assert_eq!(actual, Some(expected));
88 /// # Ok::<_, noodles_core::position::TryFromIntError>(())
89 /// ```
90 pub fn slice<I>(&self, interval: I) -> Option<Self>
91 where
92 I: Into<Interval>,
93 {
94 let interval = interval.into();
95
96 let start = interval
97 .start()
98 .map(|position| usize::from(position) - 1)
99 .unwrap_or(usize::MIN);
100
101 let end = interval.end().map(usize::from).unwrap_or(self.len());
102
103 if start <= end && end <= self.len() {
104 let buf = self.0.slice(start..end);
105 Some(Self::from(buf))
106 } else {
107 None
108 }
109 }
110
111 /// Returns an iterator that complements the sequence.
112 ///
113 /// # Examples
114 ///
115 /// ## Complement a sequence
116 ///
117 /// ```
118 /// use noodles_fasta::record::Sequence;
119 /// let sequence = Sequence::from(b"ACGT".to_vec());
120 /// let actual: Sequence = sequence.complement().collect::<Result<_, _>>()?;
121 /// let expected = Sequence::from(b"TGCA".to_vec());
122 /// assert_eq!(actual, expected);
123 /// # Ok::<_, noodles_fasta::record::sequence::complement::ComplementError>(())
124 /// ```
125 ///
126 /// ## Reverse complement a sequence
127 ///
128 /// ```
129 /// use noodles_fasta::record::Sequence;
130 /// let sequence = Sequence::from(b"ACGT".to_vec());
131 /// let actual: Sequence = sequence.complement().rev().collect::<Result<_, _>>()?;
132 /// let expected = sequence.clone();
133 /// assert_eq!(actual, expected);
134 /// # Ok::<_, noodles_fasta::record::sequence::complement::ComplementError>(())
135 /// ```
136 pub fn complement(&self) -> Complement<'_> {
137 Complement::new(self.0.iter())
138 }
139}
140
141impl AsRef<[u8]> for Sequence {
142 fn as_ref(&self) -> &[u8] {
143 &self.0
144 }
145}
146
147impl From<Vec<u8>> for Sequence {
148 fn from(data: Vec<u8>) -> Self {
149 Self(Bytes::from(data))
150 }
151}
152
153impl From<Bytes> for Sequence {
154 fn from(data: Bytes) -> Self {
155 Self(data)
156 }
157}
158
159impl FromIterator<u8> for Sequence {
160 fn from_iter<T>(iter: T) -> Self
161 where
162 T: IntoIterator<Item = u8>,
163 {
164 let mut buf = Vec::new();
165 buf.extend(iter);
166 Self::from(buf)
167 }
168}
169
170impl<I> Index<I> for Sequence
171where
172 I: SequenceIndex<u8>,
173{
174 type Output = I::Output;
175
176 fn index(&self, index: I) -> &Self::Output {
177 index.index(self.as_ref())
178 }
179}