ff_structure/
dotbracket.rs1use std::fmt;
2use std::ops::Deref;
3use std::ops::DerefMut;
4use std::convert::TryFrom;
5
6use crate::PairTable;
7use crate::MultiPairTable;
8use crate::MultiStruct;
9use crate::StrandPairTable;
10use crate::StructureError;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub enum DotBracket {
14 Unpaired, Open, Close, Break, }
19
20impl TryFrom<char> for DotBracket {
21 type Error = StructureError;
22
23 fn try_from(c: char) -> Result<Self, Self::Error> {
24 match c {
25 '.' => Ok(DotBracket::Unpaired),
26 '(' => Ok(DotBracket::Open),
27 ')' => Ok(DotBracket::Close),
28 '+' | '&' => Ok(DotBracket::Break),
29 _ => Err(StructureError::InvalidToken(c.to_string(), "dot-bracket".into(), 0)),
30 }
31 }
32}
33
34impl From<DotBracket> for char {
35 fn from(db: DotBracket) -> Self {
36 match db {
37 DotBracket::Open => '(',
38 DotBracket::Close => ')',
39 DotBracket::Unpaired => '.',
40 DotBracket::Break => '+',
41 }
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Hash)]
49pub struct DotBracketVec(pub Vec<DotBracket>);
50
51impl Deref for DotBracketVec {
52 type Target = [DotBracket];
53 fn deref(&self) -> &Self::Target {
54 &self.0
55 }
56}
57
58impl DerefMut for DotBracketVec {
59 fn deref_mut(&mut self) -> &mut Self::Target {
60 &mut self.0
61 }
62}
63
64impl TryFrom<&str> for DotBracketVec {
65 type Error = StructureError;
66
67 fn try_from(s: &str) -> Result<Self, Self::Error> {
68 let mut vec = Vec::with_capacity(s.len());
69 for (i, c) in s.chars().enumerate() {
70 match DotBracket::try_from(c) {
71 Ok(db) => vec.push(db),
72 Err(StructureError::InvalidToken(tok, src, _)) => {
73 return Err(StructureError::InvalidToken(tok, src, i));
74 }
75 Err(e) => return Err(e),
76 }
77 }
78 Ok(DotBracketVec(vec))
79 }
80}
81
82impl From<&PairTable> for DotBracketVec {
83 fn from(pt: &PairTable) -> Self {
84 let mut result: Vec<DotBracket> = Vec::with_capacity(pt.len());
85 for (i, &j_opt) in pt.iter().enumerate() {
86 match j_opt {
87 None => result.push(DotBracket::Unpaired),
88 Some(j) if (j as usize) > i => result.push(DotBracket::Open),
89 Some(j) if (j as usize) < i => result.push(DotBracket::Close),
90 Some(j) if (j as usize) == i => {
91 unreachable!("PairTable construction prevents self-pairing! ({})", i);
92 }
93 _ => unreachable!(),
94 }
95 }
96 DotBracketVec(result)
97 }
98}
99
100impl From<&MultiPairTable> for DotBracketVec {
101 fn from(mpt: &MultiPairTable) -> Self {
102 let mut db = Vec::with_capacity(mpt.len());
103
104 for (i, entry) in mpt.iter().enumerate() {
105 match entry {
106 MultiStruct::Unpaired => {
107 db.push(DotBracket::Unpaired);
108 }
109 MultiStruct::StrandBreak => {
110 db.push(DotBracket::Break);
111 }
112 MultiStruct::Paired(j) => {
113 let j = *j as usize;
114 if i < j {
115 db.push(DotBracket::Open);
116 } else {
117 db.push(DotBracket::Close);
118 }
119 }
120 }
121 }
122 DotBracketVec(db)
123 }
124}
125
126impl From<&StrandPairTable> for DotBracketVec {
127
128 fn from(pt: &StrandPairTable) -> Self {
129 let mut result: Vec<DotBracket> = Vec::with_capacity(pt.len() + pt.num_strands());
130
131 for (si, strand) in pt.iter().enumerate() {
132 for (di, &pair) in strand.iter().enumerate() {
133 match pair {
134 None => result.push(DotBracket::Unpaired),
135 Some((sj, dj)) => {
136 let sj = sj as usize;
137 let dj = dj as usize;
138 if (sj, dj) > (si, di) {
139 result.push(DotBracket::Open);
140 } else if (sj, dj) < (si, di) {
141 result.push(DotBracket::Close);
142 } else {
143 panic!("Invalid self-pairing at strand {si}, domain {di}");
144 }
145 }
146 }
147 }
148 result.push(DotBracket::Break);
151 }
152
153 DotBracketVec(result)
154 }
155}
156
157impl fmt::Display for DotBracketVec {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 for db in &self.0 {
160 write!(f, "{}", char::from(*db))?;
161 }
162 Ok(())
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn test_dot_bracket_from_char() {
172 assert_eq!(DotBracket::try_from('.').unwrap(), DotBracket::Unpaired);
173 assert_eq!(DotBracket::try_from('(').unwrap(), DotBracket::Open);
174 assert_eq!(DotBracket::try_from(')').unwrap(), DotBracket::Close);
175 }
176
177 #[test]
178 fn test_char_from_dot_bracket() {
179 assert_eq!(char::from(DotBracket::Unpaired), '.');
180 assert_eq!(char::from(DotBracket::Open), '(');
181 assert_eq!(char::from(DotBracket::Close), ')');
182 }
183
184 #[test]
185 fn test_dot_bracket_from_invalid_char() {
186 let res = DotBracket::try_from('x');
187 assert!(matches!(res, Err(StructureError::InvalidToken(_, src, _)) if src == "dot-bracket"));
188 }
189
190 #[test]
191 fn test_dot_bracket_vec_from_str() {
192 let dbv = DotBracketVec::try_from("(.).").unwrap();
193 assert_eq!(format!("{}", dbv), "(.).");
194 assert_eq!(dbv.len(), 4);
195 assert_eq!(dbv[0], DotBracket::Open);
196 assert_eq!(dbv[1], DotBracket::Unpaired);
197 assert_eq!(dbv[2], DotBracket::Close);
198 assert_eq!(dbv[3], DotBracket::Unpaired);
199 }
200
201 #[test]
202 fn test_dot_bracket_vec_from_pair_table() {
203 let pt = PairTable::try_from("((..))").unwrap();
204 let dbv = DotBracketVec::from(&pt);
205 assert_eq!(format!("{}", dbv), "((..))");
206 }
207
208 #[test]
209 fn test_dot_bracket_vec_from_multi_pair_table_hack() {
210 let pt = StrandPairTable::try_from("((..))+").unwrap();
211 let dbv = DotBracketVec::from(&pt);
212 assert_eq!(format!("{}", dbv), "((..))+");
213 }
214
215 #[test]
216 fn test_dot_bracket_vec_from_multi_pair_table() {
217 let pt = StrandPairTable::try_from("((..)+)").unwrap();
218 let dbv = DotBracketVec::from(&pt);
219 assert_eq!(format!("{}", dbv), "((..)+)+");
220 }
221
222}
223