exon_mzml/mzml_reader/
binary_conversion.rs

1// Copyright 2023 WHERE TRUE Technologies.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use flate2::read::ZlibDecoder;
16use std::io::prelude::*;
17
18use byteorder::{LittleEndian, ReadBytesExt};
19use std::io::Cursor;
20
21use base64::Engine;
22
23use super::types::{Binary, CompressionType, DataType};
24
25/// Convert the binary content into a float of the appropriate type.
26pub fn decode_binary_array(
27    b: &Binary,
28    ct: &CompressionType,
29    dt: &DataType,
30) -> std::io::Result<Vec<f64>> {
31    let decoded = match &b.content {
32        Some(c) => c,
33        None => {
34            return Err(std::io::Error::new(
35                std::io::ErrorKind::InvalidData,
36                "No binary content found.",
37            ))
38        }
39    };
40
41    let decoded = base64::engine::general_purpose::STANDARD
42        .decode(decoded)
43        .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
44
45    match (ct, dt) {
46        (CompressionType::NoCompression, DataType::Float32Bit) => {
47            Ok(binary_string_to_array_f32(decoded))
48        }
49        (CompressionType::NoCompression, DataType::Float64Bit) => {
50            Ok(binary_string_to_array_f64(decoded))
51        }
52        (CompressionType::ZlibCompression, DataType::Float64Bit) => {
53            let mut decoded_bytes = Vec::<u8>::new();
54
55            let rdr = Cursor::new(decoded);
56
57            let mut d = ZlibDecoder::new(rdr);
58            d.read_to_end(&mut decoded_bytes).unwrap();
59
60            Ok(binary_string_to_array_f64(decoded_bytes))
61        }
62        (CompressionType::ZlibCompression, DataType::Float32Bit) => {
63            let mut decoded_bytes = Vec::<u8>::new();
64
65            let rdr = Cursor::new(decoded);
66
67            let mut d = ZlibDecoder::new(rdr);
68            d.read_to_end(&mut decoded_bytes).unwrap();
69
70            Ok(binary_string_to_array_f32(decoded_bytes))
71        }
72    }
73}
74
75pub fn binary_string_to_array_f32(decoded: Vec<u8>) -> Vec<f64> {
76    let mut rdr = Cursor::new(decoded);
77
78    let mut peaks = Vec::<f64>::new();
79    while let Ok(fl) = rdr.read_f32::<LittleEndian>() {
80        peaks.push(f64::from(fl));
81    }
82
83    peaks
84}
85
86pub fn binary_string_to_array_f64(decoded: Vec<u8>) -> Vec<f64> {
87    let mut rdr = Cursor::new(decoded);
88
89    let mut peaks = Vec::<f64>::new();
90    while let Ok(fl) = rdr.read_f64::<LittleEndian>() {
91        peaks.push(fl);
92    }
93
94    peaks
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn parse_mzml_test() {
103        struct TestData {
104            binary: Binary,
105            compression_type: CompressionType,
106            data_type: DataType,
107            expected_array: Vec<f64>,
108        }
109
110        impl TestData {
111            pub fn new(
112                binary: Binary,
113                compression_type: CompressionType,
114                data_type: DataType,
115                expected_array: Vec<f64>,
116            ) -> Self {
117                Self {
118                    binary,
119                    compression_type,
120                    data_type,
121                    expected_array,
122                }
123            }
124        }
125
126        let tests = [
127            TestData::new(Binary::new(Some(String::from("AAAAAAAALkAAAAAAAAAsQAAAAAAAACpAAAAAAAAAKEAAAAAAAAAmQAAAAAAAACRAAAAAAAAAIkAAAAAAAAAgQAAAAAAAABxAAAAAAAAAGEAAAAAAAAAUQAAAAAAAABBAAAAAAAAACEAAAAAAAAAAQAAAAAAAAPA/"))), CompressionType::NoCompression, DataType::Float64Bit, vec![15.0, 14.0, 13.0, 12.0, 11.0, 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0]),
128            TestData::new(Binary::new(Some(String::from("eJxjYEABDhBKAEpLQGkFKK0CpTWgtA6UNoDSRg4AZlQDYw=="))), CompressionType::ZlibCompression, DataType::Float64Bit, vec![0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0])
129        ];
130
131        for test in tests.iter() {
132            let array =
133                decode_binary_array(&test.binary, &test.compression_type, &test.data_type).unwrap();
134            assert_eq!(array, test.expected_array);
135        }
136    }
137}