noodles_sam/header/builder.rs
1use bstr::BString;
2
3use super::{
4 record::value::{
5 map::{self, Program, ReadGroup, ReferenceSequence},
6 Map,
7 },
8 Header, Programs, ReadGroups, ReferenceSequences,
9};
10
11/// A SAM header builder.
12#[derive(Debug, Default)]
13pub struct Builder {
14 header: Option<Map<map::Header>>,
15 reference_sequences: ReferenceSequences,
16 read_groups: ReadGroups,
17 programs: Programs,
18 comments: Vec<BString>,
19}
20
21impl Builder {
22 /// Sets a SAM header header.
23 ///
24 /// # Examples
25 ///
26 /// ```
27 /// use noodles_sam as sam;
28 ///
29 /// let header = sam::Header::builder()
30 /// .set_header(Default::default())
31 /// .build();
32 ///
33 /// assert!(header.header().is_some());
34 /// ```
35 pub fn set_header(mut self, header: Map<map::Header>) -> Self {
36 self.header = Some(header);
37 self
38 }
39
40 /// Sets the reference sequences.
41 ///
42 /// # Examples
43 ///
44 /// ```
45 /// use std::num::NonZeroUsize;
46 ///
47 /// use bstr::BString;
48 /// use noodles_sam::{
49 /// self as sam,
50 /// header::record::value::{map::ReferenceSequence, Map},
51 /// };
52 ///
53 /// let reference_sequences = [(
54 /// BString::from("sq0"),
55 /// Map::<ReferenceSequence>::new(NonZeroUsize::try_from(13)?),
56 /// )]
57 /// .into_iter()
58 /// .collect();
59 ///
60 /// let header = sam::Header::builder()
61 /// .set_reference_sequences(reference_sequences)
62 /// .build();
63 ///
64 /// let reference_sequences = header.reference_sequences();
65 /// assert_eq!(reference_sequences.len(), 1);
66 /// assert!(reference_sequences.contains_key(&b"sq0"[..]));
67 /// # Ok::<(), std::num::TryFromIntError>(())
68 /// ```
69 pub fn set_reference_sequences(mut self, reference_sequences: ReferenceSequences) -> Self {
70 self.reference_sequences = reference_sequences;
71 self
72 }
73
74 /// Adds a reference sequence to the SAM header.
75 ///
76 /// # Examples
77 ///
78 /// ```
79 /// use std::num::NonZeroUsize;
80 ///
81 /// use noodles_sam::{
82 /// self as sam,
83 /// header::record::value::{map::ReferenceSequence, Map},
84 /// };
85 ///
86 /// let header = sam::Header::builder()
87 /// .add_reference_sequence(
88 /// "sq0",
89 /// Map::<ReferenceSequence>::new(NonZeroUsize::try_from(13)?),
90 /// )
91 /// .build();
92 ///
93 /// let reference_sequences = header.reference_sequences();
94 /// assert_eq!(reference_sequences.len(), 1);
95 /// assert!(reference_sequences.contains_key(&b"sq0"[..]));
96 /// # Ok::<(), Box<dyn std::error::Error>>(())
97 /// ```
98 pub fn add_reference_sequence<N>(
99 mut self,
100 name: N,
101 reference_sequence: Map<ReferenceSequence>,
102 ) -> Self
103 where
104 N: Into<BString>,
105 {
106 self.reference_sequences
107 .insert(name.into(), reference_sequence);
108
109 self
110 }
111
112 /// Adds a read group to the SAM header.
113 ///
114 /// # Examples
115 ///
116 /// ```
117 /// use noodles_sam::{
118 /// self as sam,
119 /// header::record::value::{map::ReadGroup, Map},
120 /// };
121 ///
122 /// let header = sam::Header::builder()
123 /// .add_read_group("rg0", Map::<ReadGroup>::default())
124 /// .build();
125 ///
126 /// let read_groups = header.read_groups();
127 /// assert_eq!(read_groups.len(), 1);
128 /// assert!(read_groups.contains_key(&b"rg0"[..]));
129 /// ```
130 pub fn add_read_group<I>(mut self, id: I, map: Map<ReadGroup>) -> Self
131 where
132 I: Into<BString>,
133 {
134 self.read_groups.insert(id.into(), map);
135 self
136 }
137
138 /// Adds a program to the SAM header.
139 ///
140 /// # Examples
141 ///
142 /// ```
143 /// use noodles_sam::{self as sam, header::record::value::{map::Program, Map}};
144 ///
145 /// let header = sam::Header::builder()
146 /// .add_program("noodles-sam", Map::<Program>::default())
147 /// .build();
148 ///
149 /// let programs = header.programs();
150 /// assert_eq!(programs.as_ref().len(), 1);
151 /// assert!(programs.as_ref().contains_key(&b"noodles-sam"[..]));
152 /// ```
153 pub fn add_program<I>(mut self, id: I, map: Map<Program>) -> Self
154 where
155 I: Into<BString>,
156 {
157 self.programs.as_mut().insert(id.into(), map);
158 self
159 }
160
161 /// Adds a comment to the SAM header.
162 ///
163 /// # Examples
164 ///
165 /// ```
166 /// use noodles_sam as sam;
167 /// let header = sam::Header::builder().add_comment("noodles-sam").build();
168 /// let comments = header.comments();
169 /// assert_eq!(comments.len(), 1);
170 /// assert_eq!(&comments[0], &b"noodles-sam"[..]);
171 /// ```
172 pub fn add_comment<C>(mut self, comment: C) -> Self
173 where
174 C: Into<BString>,
175 {
176 self.comments.push(comment.into());
177 self
178 }
179
180 /// Builds a SAM header.
181 ///
182 /// # Examples
183 ///
184 /// ```
185 /// use noodles_sam as sam;
186 /// let header = sam::Header::builder().build();
187 /// assert!(header.is_empty());
188 /// ```
189 pub fn build(self) -> Header {
190 Header {
191 header: self.header,
192 reference_sequences: self.reference_sequences,
193 read_groups: self.read_groups,
194 programs: self.programs,
195 comments: self.comments,
196 }
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn test_default() {
206 let header = Builder::default();
207
208 assert!(header.header.is_none());
209 assert!(header.reference_sequences.is_empty());
210 assert!(header.read_groups.is_empty());
211 assert!(header.programs.as_ref().is_empty());
212 assert!(header.comments.is_empty());
213 }
214
215 #[test]
216 fn test_build() -> Result<(), Box<dyn std::error::Error>> {
217 use std::num::NonZeroUsize;
218
219 let header = Builder::default()
220 .add_reference_sequence(
221 "sq0",
222 Map::<ReferenceSequence>::new(NonZeroUsize::try_from(8)?),
223 )
224 .add_reference_sequence(
225 "sq1",
226 Map::<ReferenceSequence>::new(NonZeroUsize::try_from(13)?),
227 )
228 .add_reference_sequence(
229 "sq2",
230 Map::<ReferenceSequence>::new(NonZeroUsize::try_from(21)?),
231 )
232 .add_read_group("rg0", Map::<ReadGroup>::default())
233 .add_read_group("rg1", Map::<ReadGroup>::default())
234 .add_program("pg0", Map::<Program>::default())
235 .add_comment("written by noodles-sam")
236 .build();
237
238 let reference_sequences = header.reference_sequences();
239 assert_eq!(reference_sequences.len(), 3);
240 assert!(reference_sequences.contains_key(&b"sq0"[..]));
241 assert!(reference_sequences.contains_key(&b"sq1"[..]));
242 assert!(reference_sequences.contains_key(&b"sq2"[..]));
243
244 assert_eq!(header.read_groups().len(), 2);
245
246 assert_eq!(header.programs().as_ref().len(), 1);
247
248 let comments = header.comments();
249 assert_eq!(comments.len(), 1);
250 assert_eq!(&comments[0], &b"written by noodles-sam"[..]);
251
252 Ok(())
253 }
254}