rinex_qc_traits/processing/
mod.rs1use std::str::FromStr;
3use thiserror::Error;
4
5mod item;
6pub use item::{FilterItem, ItemError};
7
8mod mask;
9pub use mask::{Error as MaskError, MaskFilter, MaskOperand, Masking};
10
11mod decim;
12pub use decim::{Decimate, DecimationFilter, DecimationFilterType, Error as DecimationError};
13
14pub trait Preprocessing: Masking + Decimate {
17 fn filter(&self, filter: &Filter) -> Self
19 where
20 Self: Sized,
21 {
22 match filter {
23 Filter::Mask(f) => self.mask(f),
24 Filter::Decimation(f) => self.decimate(f),
25 }
26 }
27 fn filter_mut(&mut self, filter: &Filter) {
29 match filter {
30 Filter::Mask(f) => self.mask_mut(f),
31 Filter::Decimation(f) => self.decimate_mut(f),
32 }
33 }
34}
35
36#[derive(Debug, Copy, Clone)]
38pub enum Repair {
39 Zero,
41}
42
43pub trait RepairTrait {
44 fn repair(&self, r: Repair) -> Self;
45 fn repair_mut(&mut self, r: Repair);
46}
47
48#[derive(Error, Debug)]
49pub enum Error {
50 #[error("invalid filter")]
51 InvalidFilter,
52 #[error("unknown filter type \"{0}\"")]
53 UnknownFilterType(String),
54 #[error("invalid mask filter")]
55 MaskFilterParsing(#[from] MaskError),
56 #[error("invalid filter item")]
57 FilterItemError(#[from] ItemError),
58 #[error("invalid decimation filter")]
59 DecimationFilterParsing(#[from] DecimationError),
60}
61
62#[derive(Debug, Clone, PartialEq)]
66pub enum Filter {
67 Mask(MaskFilter),
69 Decimation(DecimationFilter),
71 }
74
75impl Filter {
76 pub fn mask(operand: MaskOperand, item: FilterItem) -> Self {
78 Self::Mask(MaskFilter { operand, item })
79 }
80 pub fn equals(item: &str) -> Result<Self, ItemError> {
83 let item = FilterItem::from_str(item)?;
84 Ok(Self::mask(MaskOperand::Equals, item))
85 }
86 pub fn not_equals(item: &str) -> Result<Self, ItemError> {
89 let item = FilterItem::from_str(item)?;
90 Ok(Self::mask(MaskOperand::NotEquals, item))
91 }
92 pub fn greater_than(item: &str) -> Result<Self, ItemError> {
95 let item = FilterItem::from_str(item)?;
96 Ok(Self::mask(MaskOperand::GreaterThan, item))
97 }
98 pub fn greater_equals(item: &str) -> Result<Self, ItemError> {
101 let item = FilterItem::from_str(item)?;
102 Ok(Self::mask(MaskOperand::GreaterEquals, item))
103 }
104 pub fn lower_equals(item: &str) -> Result<Self, ItemError> {
107 let item = FilterItem::from_str(item)?;
108 Ok(Self::mask(MaskOperand::LowerEquals, item))
109 }
110 pub fn lower_than(item: &str) -> Result<Self, ItemError> {
113 let item = FilterItem::from_str(item)?;
114 Ok(Self::mask(MaskOperand::LowerThan, item))
115 }
116}
117
118impl From<MaskFilter> for Filter {
119 fn from(mask: MaskFilter) -> Self {
120 Self::Mask(mask)
121 }
122}
123
124impl std::ops::Not for Filter {
125 type Output = Self;
126 fn not(self) -> Self {
127 match self {
128 Self::Mask(f) => Self::Mask(!f),
129 _ => self.clone(), }
131 }
132}
133
134impl From<DecimationFilter> for Filter {
135 fn from(decim: decim::DecimationFilter) -> Self {
136 Self::Decimation(decim)
137 }
138}
139
140impl std::str::FromStr for Filter {
141 type Err = Error;
142 fn from_str(content: &str) -> Result<Self, Self::Err> {
143 let items: Vec<&str> = content.split(':').collect();
144
145 let identifier = items[0].trim();
146 if identifier.eq("decim") {
147 let offset = 6; Ok(Self::Decimation(DecimationFilter::from_str(
149 content[offset..].trim(),
150 )?))
151 } else if identifier.eq("mask") {
152 let offset = 5; Ok(Self::Mask(MaskFilter::from_str(content[offset..].trim())?))
154 } else {
155 if let Ok(f) = MaskFilter::from_str(content.trim()) {
157 Ok(Self::Mask(f))
158 } else {
159 Err(Error::UnknownFilterType(content.to_string()))
160 }
161 }
162 }
163}
164
165#[cfg(test)]
166mod test {
167 use super::*;
168 use std::str::FromStr;
169 #[test]
170 fn from_str() {
171 for descriptor in [
175 "GPS",
176 "=GPS",
177 " != GPS",
178 "G08, G09, G10",
179 "=G08, G09, G10",
180 "!= GPS, GAL",
181 ">G08, G09",
182 "iode",
183 "iode,gps",
184 "iode,crs,gps",
185 "iode,crs",
186 ">2020-01-14T00:31:55 UTC",
187 ] {
188 assert!(
189 Filter::from_str(descriptor).is_ok(),
190 "Filter::from_str failed on \"{}\"",
191 descriptor
192 );
193 }
194 for desc in [
198 "decim:10",
199 "decim:10 min",
200 "decim:1 hour",
201 "decim:10 min:l1c",
202 "decim:1 hour:L1C,L2C,L3C",
203 ] {
204 let filt = Filter::from_str(desc);
205 assert!(filt.is_ok(), "Filter::from_str failed on \"{}\"", desc);
206 }
207 for desc in [
211 "smooth:mov:10 min",
212 "smooth:mov:1 hour",
213 "smooth:mov:1 hour:l1c",
214 "smooth:mov:10 min:clk",
215 "smooth:hatch",
216 "smooth:hatch:l1c",
217 ] {
218 let filt = Filter::from_str(desc);
219 assert!(filt.is_ok(), "Filter::from_str failed on \"{}\"", desc);
220 }
221 }
222}