1use flate2::bufread::ZlibDecoder;
2use quick_xml::events::{BytesStart, Event};
3use std::collections::VecDeque;
4use std::io::{BufRead, Cursor, Read, Write};
5
6use super::cvparam::{search_all_params, CVParam, HasCVParams, HasParamGroupRefs};
7use super::writer::Writer;
8use super::{MzMLReader, MzMLTag, Tag};
9use crate::error::{FatalParseError, ParseError};
10use crate::mzml::attributes::{AttributeValue, LIST_ATTRIBUTES};
11use crate::mzml::cvparam::{CVParamValue, RawTerm, UserParam};
12
13use super::referenceableparamgroup::ReferenceableParamGroupRef;
14
15pub const ACCESSION_MZ_ARRAY: &str = "MS:1000514";
17pub const ACCESSION_INTENSITY_ARRAY: &str = "MS:1000515";
19
20pub const ACCESSION_BINARY_DATA_TYPE: &str = "MS:1000518";
22pub const ACCESSION_64_BIT_FLOAT: &str = "MS:1000523";
24pub const ACCESSION_32_BIT_FLOAT: &str = "MS:1000521";
26
27pub const ACCESSION_COMPRESSION: &str = "MS:1000572";
29pub const ACCESSION_NO_COMPRESSION: &str = "MS:1000576";
31pub const ACCESSION_ZLIB_COMPRESSION: &str = "MS:1000574";
33
34pub const ACCESSION_EXTERNAL_ARRAY_LENGTH: &str = "IMS:1000103";
36const B_ACCESSION_EXTERNAL_ARRAY_LENGTH: &[u8] = b"IMS:1000103";
37
38pub const ACCESSION_EXTERNAL_ENCODED_LENGTH: &str = "IMS:1000104";
40const B_ACCESSION_EXTERNAL_ENCODED_LENGTH: &[u8] = b"IMS:1000104";
41
42pub const ACCESSION_EXTERNAL_OFFSET: &str = "IMS:1000102";
44const B_ACCESSION_EXTERNAL_OFFSET: &[u8] = b"IMS:1000102";
45
46pub const ACCESSION_EXTERNAL_DATA: &str = "IMS:1000101";
48const B_ACCESSION_EXTERNAL_DATA: &[u8] = b"IMS:1000101";
49
50#[derive(Debug, PartialEq, Eq)]
52pub enum BinaryDataArrayType {
53 MZArray,
55 IntenistyArray,
57}
58
59#[derive(Debug, Clone, Copy)]
61pub enum BinaryDataType {
62 Undefined,
64 Float64,
66 Float32,
68}
69
70pub struct BinaryDataArrayList {
72 pub(crate) list: Vec<BinaryDataArray>,
74}
75
76impl BinaryDataArrayList {
77 fn new(count: usize) -> Self {
78 BinaryDataArrayList {
79 list: Vec::with_capacity(count),
80 }
81 }
82}
83
84impl MzMLTag for BinaryDataArrayList {
85 fn parse_start_tag<B: BufRead>(
86 parser: &mut MzMLReader<B>,
87 start_event: &BytesStart,
88 ) -> Result<Option<Self>, FatalParseError>
89 where
90 Self: std::marker::Sized,
91 {
92 if start_event.name().local_name().as_ref() != b"binaryDataArrayList" {
93 Err(FatalParseError::UnexpectedTag(format!(
94 "Unexpected event {:?} when processing BinaryDataArrayList",
95 start_event,
96 )))
97 } else {
98 let attributes = parser.process_attributes(
99 Tag::BinaryDataArrayList,
100 &LIST_ATTRIBUTES,
101 start_event,
102 )?;
103
104 let count = match attributes.get("count") {
105 Some(&AttributeValue::Integer(count)) => count as usize,
106 _ => 0,
107 };
108
109 parser
110 .breadcrumbs
111 .push_back((Tag::BinaryDataArrayList, None));
112
113 Ok(Some(BinaryDataArrayList::new(count)))
114 }
115 }
116
117 fn parse_xml<B: BufRead>(
118 &mut self,
119 parser: &mut MzMLReader<B>,
120 buffer: &mut Vec<u8>,
121 ) -> Result<(), FatalParseError> {
122 let mut last_num_params = 0;
123
124 loop {
126 buffer.clear();
128
129 let next_event = parser.next(buffer)?;
130
131 match next_event {
132 Event::Start(start_event) | Event::Empty(start_event) => {
133 match start_event.name().as_ref() {
134 b"binaryDataArray" => {
135 if let Some(mut bda) =
136 BinaryDataArray::parse_start_tag(parser, &start_event)?
137 {
138 bda.cv_params.reserve(last_num_params);
139 bda.parse_xml(parser, buffer)?;
140
141 last_num_params = bda.cv_params.len();
142
143 self.list.push(bda);
144 }
145 }
146 _ => parser.errors.push_back(ParseError::UnexpectedTag(format!(
147 "{:?} unexpected when processing {:?}",
148 std::str::from_utf8(start_event.name().as_ref()),
149 Tag::BinaryDataArrayList
150 ))),
151 }
152 }
153 Event::End(end_event) => {
154 if let b"binaryDataArrayList" = end_event.name().as_ref() {
155 parser.breadcrumbs.pop_back();
156
157 break;
158 }
159 }
160 Event::Eof => {
161 return Err(FatalParseError::MissingClosingTag(
162 "binaryDataArrayList".to_string(),
163 ));
164 }
165 _ => {}
166 }
167 }
168
169 Ok(())
170 }
171
172 fn tag() -> Tag {
173 Tag::BinaryDataArrayList
174 }
175
176 fn write_xml<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), quick_xml::Error> {
177 writer.write_list("binaryDataArrayList", &self.list)
178 }
179}
180
181#[derive(Debug)]
183pub enum Compression {
184 None,
186 Undefined,
188 Zlib,
190}
191
192pub struct CompressionReader {
194 reader: Box<dyn Read>,
195}
196
197impl Read for CompressionReader {
198 #[inline]
199 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
200 self.reader.read(buf)
201 }
202}
203
204impl Compression {
205 pub fn to_reader(&self, data: Vec<u8>) -> CompressionReader {
207 match self {
208 Compression::None | Compression::Undefined => CompressionReader {
209 reader: Box::new(Cursor::new(data)),
210 },
211 Compression::Zlib => CompressionReader {
212 reader: Box::new(ZlibDecoder::new(Cursor::new(data))),
213 },
214 }
215 }
216}
217
218#[derive(Debug)]
220pub struct BinaryDataArray {
221 param_group_refs: Vec<ReferenceableParamGroupRef>,
222 cv_params: Vec<CVParam>,
223 user_params: Vec<UserParam>,
224
225 is_external: bool,
226
227 array_length: Option<u64>,
228 encoded_length: Option<u64>,
229 offset: Option<u64>,
230}
231
232impl Clone for BinaryDataArray {
233 fn clone(&self) -> Self {
234 Self {
235 param_group_refs: self.param_group_refs.clone(),
236 cv_params: self.cv_params.clone(),
237 user_params: self.user_params.clone(),
238 is_external: self.is_external,
239 array_length: self.array_length,
240 encoded_length: self.encoded_length,
241 offset: self.offset,
242 }
243 }
244}
245
246impl Default for BinaryDataArray {
247 fn default() -> Self {
248 Self::new()
249 }
250}
251
252impl BinaryDataArray {
253 pub fn new() -> Self {
255 BinaryDataArray {
256 param_group_refs: Vec::new(),
257 cv_params: Vec::new(),
258 user_params: Vec::new(),
259
260 is_external: true,
261
262 array_length: None,
263 encoded_length: None,
264 offset: None,
265 }
266 }
267
268 pub(crate) fn set_external_params(
269 &mut self,
270 offset: u64,
271 array_length: u64,
272 encoded_length: u64,
273 ) {
274 self.is_external = true;
275 self.offset = Some(offset);
276 self.array_length = Some(array_length);
277 self.encoded_length = Some(encoded_length);
278 }
279
280 pub fn array_type(&self) -> Option<BinaryDataArrayType> {
282 if let Some(_cv_param) = search_all_params(self, ACCESSION_MZ_ARRAY) {
283 return Some(BinaryDataArrayType::MZArray);
284 }
285 if let Some(_cv_param) = search_all_params(self, ACCESSION_INTENSITY_ARRAY) {
286 return Some(BinaryDataArrayType::IntenistyArray);
287 }
288 None
289 }
290
291 pub fn binary_type(&self) -> BinaryDataType {
293 if let Some(_cv_param) = search_all_params(self, ACCESSION_64_BIT_FLOAT) {
294 return BinaryDataType::Float64;
295 }
296 if let Some(_cv_param) = search_all_params(self, ACCESSION_32_BIT_FLOAT) {
297 return BinaryDataType::Float32;
298 }
299
300 BinaryDataType::Undefined
301 }
302
303 pub fn compression(&self) -> Compression {
305 if let Some(_cv_param) = search_all_params(self, ACCESSION_NO_COMPRESSION) {
306 return Compression::None;
307 }
308 if let Some(_cv_param) = search_all_params(self, ACCESSION_ZLIB_COMPRESSION) {
309 return Compression::Zlib;
310 }
311
312 Compression::Undefined
313 }
314
315 pub fn array_length(&self) -> Option<u64> {
317 self.array_length
318 }
319
320 pub fn encoded_length(&self) -> Option<u64> {
322 self.encoded_length
323 }
324
325 pub fn offset(&self) -> Option<u64> {
327 self.offset
328 }
329
330 pub fn is_data_external(&self) -> bool {
332 self.is_external
333 }
334
335 pub(crate) fn add_raw_term<'a>(
336 &mut self,
337 raw_term: &RawTerm<'a>,
338 breadcrumbs: &VecDeque<(Tag, Option<String>)>,
339 errors: &mut VecDeque<ParseError>,
340 ignore_uncommon_tags: bool,
341 ) {
342 match raw_term.raw_accession() {
343 B_ACCESSION_EXTERNAL_ARRAY_LENGTH => {
344 self.array_length = Some(raw_term.value_as_u64());
345 }
346 B_ACCESSION_EXTERNAL_ENCODED_LENGTH => {
347 self.encoded_length = Some(raw_term.value_as_u64());
348 }
349 B_ACCESSION_EXTERNAL_OFFSET => {
350 self.offset = Some(raw_term.value_as_u64());
351 }
352 B_ACCESSION_EXTERNAL_DATA => {}
353 _ => {
354 if !ignore_uncommon_tags {
357 self.cv_params
358 .push(raw_term.to_cv_param(breadcrumbs, errors))
359 }
360 }
361 }
362 }
363}
364
365impl MzMLTag for BinaryDataArray {
366 fn parse_start_tag<B: BufRead>(
367 parser: &mut MzMLReader<B>,
368 start_event: &BytesStart,
369 ) -> Result<Option<Self>, FatalParseError>
370 where
371 Self: std::marker::Sized,
372 {
373 if start_event.name().local_name().as_ref() != b"binaryDataArray" {
374 Err(FatalParseError::UnexpectedTag(format!(
375 "Unexpected event {:?} when processing BinaryDataArray",
376 start_event,
377 )))
378 } else {
379 parser.breadcrumbs.push_back((Tag::BinaryDataArray, None));
382
383 Ok(Some(BinaryDataArray::new()))
384 }
385 }
386
387 fn parse_xml<B: BufRead>(
388 &mut self,
389 parser: &mut MzMLReader<B>,
390 buffer: &mut Vec<u8>,
391 ) -> Result<(), FatalParseError> {
392 loop {
394 buffer.clear();
396
397 let next_event = parser.next(buffer)?;
398 let is_empty = matches!(next_event, Event::Empty(_));
399
400 match next_event {
401 Event::Start(start_event) | Event::Empty(start_event) => {
402 match start_event.name().as_ref() {
403 b"cvParam" => {
404 let raw_term = RawTerm::parse_start_tag(parser, &start_event)?;
405 self.add_raw_term(
406 &raw_term,
407 &parser.breadcrumbs,
408 &mut parser.errors,
409 parser.ignore_uncommon_tags,
410 );
411 }
412 b"referenceableParamGroupRef" => {
413 let param_group_ref =
414 ReferenceableParamGroupRef::parse_start_tag(parser, &start_event)?;
415 self.param_group_refs.push(param_group_ref);
416 }
417 b"binary" => {
418 if !is_empty && self.offset.is_none() {
419 self.is_external = false;
420
421 self.offset = Some(parser.reader.buffer_position() as u64);
422 }
423 }
424 _ => parser.errors.push_back(ParseError::UnexpectedTag(format!(
425 "{:?} unexpected when processing {:?}",
426 std::str::from_utf8(start_event.name().as_ref()),
427 Tag::BinaryDataArray
428 ))),
429 }
430 }
431 Event::Text(_) => {
432 if !self.is_external {
433 self.encoded_length =
434 Some(parser.reader.buffer_position() as u64 - self.offset.unwrap());
435 }
436 }
437 Event::End(end_event) => {
438 if let b"binaryDataArray" = end_event.name().as_ref() {
439 parser.breadcrumbs.pop_back();
447
448 break;
449 }
450 }
451 Event::Eof => {
452 return Err(FatalParseError::MissingClosingTag(
453 "binaryDataArray".to_string(),
454 ));
455 }
456 _ => {}
457 }
458 }
459
460 Ok(())
461 }
462
463 fn tag() -> Tag {
464 Tag::BinaryDataArray
465 }
466
467 fn write_xml<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), quick_xml::Error> {
468 writer.start_tag_with_attr(
469 "binaryDataArray",
470 "encodedLength",
471 self.encoded_length.unwrap_or(0),
472 )?;
473
474 self.write_ref_param_groups_xml(writer)?;
475
476 if let Some(array_length) = self.array_length {
477 writer.write_param(
478 ACCESSION_EXTERNAL_ARRAY_LENGTH,
479 CVParamValue::NonNegativeInteger(array_length),
480 )?;
481 }
482
483 if let Some(encoded_length) = self.encoded_length {
484 writer.write_param(
485 ACCESSION_EXTERNAL_ENCODED_LENGTH,
486 CVParamValue::NonNegativeInteger(encoded_length),
487 )?;
488 }
489
490 if let Some(offset) = self.offset {
491 writer.write_param(
492 ACCESSION_EXTERNAL_OFFSET,
493 CVParamValue::NonNegativeInteger(offset),
494 )?;
495 }
496
497 writer.write_param(ACCESSION_EXTERNAL_DATA, CVParamValue::Empty)?;
500
501 self.write_params_xml(writer)?;
502
503 writer.empty_tag("binary")?;
504 writer.end_tag("binaryDataArray")
505 }
506}
507
508impl HasCVParams for BinaryDataArray {
532 fn add_cv_param(&mut self, param: CVParam) {
533 match param.accession() {
534 ACCESSION_EXTERNAL_ARRAY_LENGTH => {
535 self.array_length = Some(param.value_as_u64().unwrap());
536 }
537 ACCESSION_EXTERNAL_ENCODED_LENGTH => {
538 self.encoded_length = Some(param.value_as_u64().unwrap());
539 }
540 ACCESSION_EXTERNAL_OFFSET => {
541 self.offset = Some(param.value_as_u64().unwrap());
542 }
543 ACCESSION_EXTERNAL_DATA => {}
544 _ => {
549 self.cv_params.push(param);
550 }
551 }
552 }
553
554 fn cv_params(&self) -> &Vec<CVParam> {
555 &self.cv_params
556 }
557
558 fn cv_params_mut(&mut self) -> &mut Vec<CVParam> {
559 self.cv_params.as_mut()
560 }
561
562 fn add_user_param(&mut self, param: UserParam) {
563 self.user_params.push(param);
564 }
565
566 fn user_params(&self) -> &Vec<UserParam> {
567 &self.user_params
568 }
569
570 }
578
579impl HasParamGroupRefs for BinaryDataArray {
580 fn add_param_group_ref(&mut self, param_group_ref: ReferenceableParamGroupRef) {
581 self.param_group_refs.push(param_group_ref);
582 }
583
584 fn param_group_refs(&self) -> &Vec<ReferenceableParamGroupRef> {
585 &self.param_group_refs
586 }
587}
588
589