use super::ParameterCollection;
#[derive(Debug, Clone, Default)]
pub struct UnknownFields {
params: ParameterCollection,
binary: Vec<u8>,
param_order: Vec<String>,
}
impl UnknownFields {
pub fn new() -> Self {
Self::default()
}
pub fn from_remaining_params(original: &ParameterCollection, known_keys: &[&str]) -> Self {
Self::from_remaining_params_with_prefixes(original, known_keys, &[])
}
pub fn from_remaining_params_with_prefixes(
original: &ParameterCollection,
known_keys: &[&str],
indexed_prefixes: &[&str],
) -> Self {
let mut params = ParameterCollection::new();
let mut param_order = Vec::new();
let known_upper: Vec<String> = known_keys.iter().map(|k| k.to_uppercase()).collect();
let prefixes_upper: Vec<String> =
indexed_prefixes.iter().map(|p| p.to_uppercase()).collect();
for (key, value) in original.iter() {
let key_upper = key.to_uppercase();
if known_upper.contains(&key_upper) {
continue;
}
let is_indexed = prefixes_upper.iter().any(|prefix| {
if key_upper.starts_with(prefix) {
let suffix = &key_upper[prefix.len()..];
suffix
.chars()
.next()
.map(|c| c.is_ascii_digit())
.unwrap_or(false)
} else {
false
}
});
if !is_indexed {
params.add(key, value.as_str());
param_order.push(key.to_string());
}
}
UnknownFields {
params,
binary: Vec::new(),
param_order,
}
}
pub fn from_remaining_binary(data: Vec<u8>) -> Self {
UnknownFields {
params: ParameterCollection::new(),
binary: data,
param_order: Vec::new(),
}
}
pub fn merge_into_params(&self, params: &mut ParameterCollection) {
for key in &self.param_order {
if let Some(value) = self.params.get(key) {
params.add(key, value.as_str());
}
}
}
pub fn binary_data(&self) -> &[u8] {
&self.binary
}
pub fn binary_data_mut(&mut self) -> &mut Vec<u8> {
&mut self.binary
}
pub fn is_empty(&self) -> bool {
self.params.is_empty() && self.binary.is_empty()
}
pub fn param_count(&self) -> usize {
self.param_order.len()
}
pub fn binary_count(&self) -> usize {
self.binary.len()
}
pub fn unknown_param_names(&self) -> &[String] {
&self.param_order
}
pub fn get_param(&self, key: &str) -> Option<String> {
self.params.get(key).map(|v| v.as_str().to_string())
}
pub fn set_param(&mut self, key: &str, value: &str) {
if self.params.get(key).is_none() {
self.param_order.push(key.to_string());
}
self.params.add(key, value);
}
pub fn remove_param(&mut self, key: &str) -> bool {
if self.params.get(key).is_some() {
self.param_order.retain(|k| k != key);
true
} else {
false
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_remaining_params() {
let mut original = ParameterCollection::new();
original.add("RECORD", "1");
original.add("NAME", "Test");
original.add("UNKNOWN1", "foo");
original.add("UNKNOWN2", "bar");
let known = &["RECORD", "NAME"];
let unknown = UnknownFields::from_remaining_params(&original, known);
assert_eq!(unknown.param_count(), 2);
assert_eq!(unknown.get_param("UNKNOWN1"), Some("foo".to_string()));
assert_eq!(unknown.get_param("UNKNOWN2"), Some("bar".to_string()));
}
#[test]
fn test_merge_into_params() {
let mut unknown = UnknownFields::new();
unknown.set_param("EXTRA1", "value1");
unknown.set_param("EXTRA2", "value2");
let mut params = ParameterCollection::new();
params.add("RECORD", "1");
unknown.merge_into_params(&mut params);
assert!(params.get("EXTRA1").is_some());
assert!(params.get("EXTRA2").is_some());
}
}