use bitvec::prelude::*;
use regex::Regex;
use std::collections::BTreeMap;
use crate::asterix::message::AsterixMessage;
use crate::asterix::category::{CategoryIndex, CategoryKey};
use crate::asterix::uap::providers::Provider;
use crate::asterix::uap_json::enums::{ConstraintType, DataItemType, DataItemValueType};
use crate::asterix::uap_json::errors::ParseError;
use crate::asterix::uap_json::structures::{DataRecord, Edition, FSpecInfo};
use crate::asterix::category::Category;
use crate::asterix::uap_json::enums::{AttributeConstraintLimit, AttributeItem, AttributeLsb, AttributeType, AttributeValueType, DataType, DenominatorType, ElementType, ElementValueType, LsbType, Uap};
use crate::asterix::uap_json::structures::{Attribute, AttributeConstraint, DataItemRule};
use crate::asterix::Context;
pub fn parse_record(
octets: &Vec<u8>,
informed_provider: Option<Provider>,
informed_edition: Option<Edition>,
debugging: bool) -> anyhow::Result<AsterixMessage> {
let provider = informed_provider.unwrap_or(Provider::Standard);
let message_category = octets[0];
let context = Context::new()?;
let cat_idx = match CategoryIndex::from_u8(message_category){
Some(c) => c.clone(),
None => {
return Err(ParseError::CategoryNotFound { category_code: format!("{:03}", message_category) }.into());
}
};
let edition = informed_edition.unwrap_or(context.find_newest_edition_for_category(&cat_idx)?);
let cat_key = CategoryKey {
index: cat_idx,
edition: edition,
provider: provider
};
let data_record = context.find_definition(cat_key)?;
let message = parse_message(&data_record, &octets, debugging)?;
Ok(message)
}
pub fn parse_message(data_record: &DataRecord, octets: &Vec<u8>, debugging: bool) -> anyhow::Result<AsterixMessage> {
let mut attributes_map = BTreeMap::<String, Attribute>::new();
let asterix_context = Context::new()?;
let cat_index = match CategoryIndex::from_u8(data_record.number) {
Some(c) => c,
None => return Err(ParseError::CategoryNotFound { category_code: data_record.number.to_string() }.into())
};
let category_key = CategoryKey {
index: cat_index,
edition: data_record.edition.clone(),
provider: Provider::Standard };
let category = get_category(asterix_context, category_key, octets[0])?;
let mut category_attribute = Attribute::default();
category_attribute.name = category.key.index.as_string();
category_attribute.description = Some(category.description);
attributes_map.insert("message_category".to_string(), category_attribute);
let octets_self_intormed_length = octets[1] as usize * 256 + octets[2] as usize;
if octets_self_intormed_length != octets.len() && debugging {
println!("======================== WARNING =======================");
println!("MESSAGE LENGTH DOES NOT CORRESPOND TO CALCULATED LENGTH!");
println!("======================== WARNING =======================");
}
let category_prefix = format!("{}", category.key.index.as_str());
let mut current_index = 3 as usize;
let expected_frns = data_record.catalogue.len() as u8;
let fspec_info: FSpecInfo = get_fspec_from_octets(octets, current_index, expected_frns);
current_index += fspec_info.len as usize;
let data_items_map = find_present_data_item_definitions(
&fspec_info.fspec,
&data_record.uap,
&data_record.catalogue)?;
let mut frn_bits = BTreeMap::<u8, BitVec<u8,Msb0>>::new();
let mut calc_len_current_index = usize::from(current_index);
for data_item_entry in &data_items_map {
let data_item_length =
match &data_item_entry.1.rule {
DataItemType::ContextFree { value } => {
let primary_field_length = match value {
DataItemValueType::Element { rule:_, size } => usize::from(*size),
DataItemValueType::Group { items } => {
find_group_length_in_bits(items)?
},
DataItemValueType::Extended { items } => {
find_extended_length_in_bits(items, octets, calc_len_current_index)?
},
DataItemValueType::Repetitive { rep, variation} => {
find_repetitive_length_in_bits(rep, variation, octets, calc_len_current_index)?
},
DataItemValueType::Compound { fspec:_, items } => {
find_compound_length_in_bits(items, octets, calc_len_current_index)?
},
DataItemValueType::Explicit { expl:_ } => 0_usize, };
primary_field_length
},
};
assert_eq!(0, data_item_length%8);
let start_octet = calc_len_current_index;
let end_octet = start_octet + (data_item_length/8);
let bits = octets[start_octet..end_octet].view_bits::<Msb0>().to_bitvec();
frn_bits.insert(*data_item_entry.0, bits);
calc_len_current_index += data_item_length/8;
}
attributes_map = find_message_attributes(&category_prefix, &data_items_map, &frn_bits)?;
let asterix_message: AsterixMessage = AsterixMessage {
code: format!("{:03}", &data_record.number),
description: data_record.title.clone(),
provider: Provider::Standard.to_string(),
attributes_map: attributes_map
};
if debugging {
describe_fspec(&fspec_info);
list_present_data_item_definitions(&data_items_map);
describe_message_attributes(asterix_message.attributes_map.clone());
}
Ok(asterix_message)
}
fn find_group_length_in_bits(items: &Vec<Option<AttributeItem>>) -> anyhow::Result<usize> {
let mut len = 0_usize;
for item in items {
match item {
Some(aitem) => {
match aitem {
AttributeItem::SpareEntry { length, spare:_ } => { len += length; },
AttributeItem::AttributeEntry(aentry) => {
match &aentry.rule {
AttributeType::ContextFree { value } => match value {
AttributeValueType::Element { rule: _, size } => { len += usize::from(*size); },
_ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())}
},
}
},
}
},
None => (),
}
}
Ok(len)
}
fn get_fspec_from_octets(octets: &[u8], current_index: usize, expected_frns: u8) -> FSpecInfo {
let mut fx = true;
let mut frn:u8 = 0;
let mut fspec_info = FSpecInfo::default();
let mut local_current_index = current_index;
fspec_info.len = 1;
while fx {
let octet = octets[local_current_index];
let fx_octet = octet.view_bits::<Msb0>().to_bitvec();
let mut bit_count = 0;
for bit in fx_octet {
if bit_count == 7 {
fx = bit;
if bit {
local_current_index += 1;
fspec_info.len += 1;
}
}
else {
frn += 1;
fspec_info.fspec.insert(frn, bit);
}
bit_count += 1;
}
}
while frn < expected_frns {
frn += 1;
fspec_info.fspec.insert(frn, false);
}
fspec_info
}
fn get_fspec_from_bits(data_item_bits: BitVec<u8, Msb0>, frn_consumed_bits: usize, expected_frns: u8) -> FSpecInfo {
let mut fx = true;
let mut frn:u8 = 0;
let mut fspec_info = FSpecInfo::default();
let mut local_current_index = frn_consumed_bits;
fspec_info.len = 1;
while fx {
let start_bit = local_current_index.clone();
let end_bit = &local_current_index + 8;
let fx_octet = data_item_bits[start_bit..end_bit].to_bitvec();
let mut bit_count = 0;
for bit in fx_octet {
if bit_count == 7 {
fx = bit;
if bit {
local_current_index += 1;
fspec_info.len += 1;
}
}
else {
frn += 1;
fspec_info.fspec.insert(frn, bit);
}
bit_count += 1;
}
}
while frn < expected_frns {
frn += 1;
fspec_info.fspec.insert(frn, false);
}
fspec_info
}
fn get_category(context:Context, category_key: CategoryKey, category_octet: u8) -> anyhow::Result<Category> {
let category: Category = match context.categories.get(&category_key) {
Some(c) => c.clone(),
None => return Err((ParseError::CategoryNotFound { category_code: category_octet.to_string()}).into())
};
Ok(category.clone())
}
fn describe_fspec(fspec_info: &FSpecInfo) {
println!("FRN configuration: ");
let mut frnh = String::new();
let mut frnx = String::new();
let mut frnl: String = String::new();
for frn in &fspec_info.fspec {
frnh += format!("| {:02}", frn.0).as_str();
frnx += format!("| {:2}", if *frn.1 {"X"} else {" "}).as_str();
frnl += "+---";
}
frnl += "+";
frnh += "|";
frnx += "|";
println!("{}", frnl);
println!("{}", frnh);
println!("{}", frnl);
println!("{}", frnx);
println!("{}", frnl);
}
fn find_present_data_item_definitions<'a> (
fspec: &'a BTreeMap<u8, bool>,
uap: &Uap,
catalogue: &'a [DataItemRule]) -> anyhow::Result<BTreeMap<u8, &'a DataItemRule>> {
let mut data_items_map = BTreeMap::<u8, &DataItemRule>::new();
let uap_items = match &uap {
Uap::Uap { items } => items,
};
for frn in fspec.into_iter().filter(| x | *x.1 ) {
let index = (frn.0 - 1) as usize;
let uap_data_item = format!("{}", &uap_items[usize::from(index)]);
let catalog_entry
= catalogue.into_iter()
.find(|x| x.name == uap_data_item);
let data_item_def
= match catalog_entry {
Some(d) => d,
None => { return Err(ParseError::UapDefinitionNotFound { uap_name: uap_data_item}.into()); },
};
data_items_map.insert(*frn.0, data_item_def);
}
Ok(data_items_map)
}
fn list_present_data_item_definitions(data_items_map: &BTreeMap<u8, &DataItemRule>) {
println!();
println!("Data items present in the given message");
for present_data_item in data_items_map {
let p_frn = present_data_item.0;
let p_data_item_rule = present_data_item.1;
println!("FRN: {:02}: {}, {}", p_frn, p_data_item_rule.name, p_data_item_rule.title );
}
println!();
}
fn find_compound_length_in_bits(
items: &Vec<Option<AttributeItem>>,
octets: &Vec<u8>,
calc_len_current_index: usize) -> anyhow::Result<usize> {
let minimum_expected_frns = 7_u8;
let fspec_info: FSpecInfo = get_fspec_from_octets(octets, calc_len_current_index, minimum_expected_frns);
let mut item_count = 1_u8;
let mut items_length = usize::from(fspec_info.len)*8; for item in items {
match item {
Some(_) => (),
None => {
item_count += 1;
continue;
},
};
if fspec_info.fspec[&item_count] == false {
item_count += 1;
continue;
}
item_count += 1;
items_length += find_attribute_item_length_in_bits(item)?
}
Ok(items_length)
}
fn find_repetitive_length_in_bits(
rep: &ElementValueType,
variation: &AttributeValueType,
octets: &Vec<u8>,
calc_len_current_index: usize) -> anyhow::Result<usize> {
let mut return_size: usize;
let mut multiplier: usize = 0;
let multiplier_bits: Option<usize>;
match rep {
ElementValueType::Fx => multiplier_bits = None,
ElementValueType::Regular { size } => {
let element_len = usize::from(*size);
multiplier_bits = Some(element_len);
assert_eq!(0, multiplier%8);
let start_octet = calc_len_current_index;
let end_octet = start_octet + 1; let bitslice = octets[start_octet..end_octet].view_bits::<Msb0>();
multiplier = bitslice.load::<usize>();
},
_ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())},
};
if multiplier_bits.is_some() {
let multiplier_len = multiplier_bits.unwrap(); let repetitive_len =
match variation {
AttributeValueType::Group { items } => {
find_group_length_in_bits(items)?
},
_ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())},
};
return_size = multiplier_len + repetitive_len * multiplier;
} else {
return_size = 0;
let mut local_octet_offset = calc_len_current_index;
let mut fx_bit = true;
while fx_bit {
let fx_octet = octets[local_octet_offset].view_bits::<Msb0>();
fx_bit = fx_octet[0];
return_size += 8;
local_octet_offset += 1;
}
}
Ok(return_size)
}
fn find_extended_length_in_bits(
items: &Vec<Option<AttributeItem>>,
octets: &Vec<u8>,
calc_len_current_index: usize) -> anyhow::Result<usize> {
let mut local_current_index = calc_len_current_index;
let mut item_len = 0_usize;
let mut fx_set = true;
for item in items {
if !fx_set {
break
}
item_len += find_attribute_item_length_in_bits(&item)?;
if item_len%8 == 0 {
let bits = octets[local_current_index].view_bits::<Msb0>().to_bitvec();
if bits[7] == true {
local_current_index += 1;
} else {
fx_set = false;
}
}
}
Ok(item_len)
}
fn find_attribute_item_length_in_bits(item: &Option<AttributeItem>) -> anyhow::Result<usize> {
let item_length = match item {
Some(i) => {
let entry_len = match i {
AttributeItem::SpareEntry { length, spare } => {
if *spare {*length } else { 0_usize }
},
AttributeItem::AttributeEntry(e) => {
let a_len = match &e.rule {
AttributeType::ContextFree { value } => {
let len = match value {
AttributeValueType::Element { rule:_, size } => usize::from(*size),
AttributeValueType::Group { items } => find_group_length_in_bits(items)?, _ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())}
};
len
},
};
a_len
},
};
entry_len
},
None => 1_usize };
Ok(item_length)
}
fn find_message_attributes(
category_prefix: &String,
data_items_map: &BTreeMap<u8, &DataItemRule>,
frn_bits: &BTreeMap<u8, BitVec<u8, Msb0>>) -> anyhow::Result<BTreeMap<String, Attribute>> {
let mut found_attributes = BTreeMap::<String, Attribute>::new();
for data_item_entry in data_items_map {
let data_item_prefix = format!("I{}", &data_item_entry.1.name);
let data_item_bits = frn_bits[data_item_entry.0].to_bitvec();
let default_attribute_name:String = get_default_attribute_name(&data_item_entry.1.title);
let mut frn_consumed_bits = 0_usize;
match &data_item_entry.1.rule {
DataItemType::ContextFree { value } => match value {
DataItemValueType::Element { rule, size } => {
let mut attribute = Attribute::default();
attribute.name = format!("{}_{}_{}", *category_prefix, data_item_prefix.as_str() ,
data_item_entry.1.title.replace(" ", "_").to_uppercase().as_str());
let last_bit = frn_consumed_bits + *size as usize;
attribute.bits = data_item_bits[frn_consumed_bits..last_bit].to_bitvec();
fill_dataitem_element_attributes(rule, &mut attribute);
found_attributes.insert(attribute.name.to_owned(), attribute);
},
DataItemValueType::Group { items } => {
let group_attributes =
fill_group_attributes(&category_prefix, &data_item_prefix, items, &mut frn_consumed_bits, data_item_bits)?;
for attribute in group_attributes {
found_attributes.insert(attribute.name.to_owned(), attribute);
}
},
DataItemValueType::Extended { items } => {
let group_attributes =
fill_extended_attributes(&category_prefix, &data_item_prefix, items, &mut frn_consumed_bits, data_item_bits)?;
for attribute in group_attributes {
found_attributes.insert(attribute.name.to_owned(), attribute);
}
},
DataItemValueType::Repetitive { rep, variation } => {
let repetitive_attributes =
fill_repetitive_attributes(&category_prefix, &data_item_prefix, rep, variation,
&mut frn_consumed_bits, data_item_bits, &default_attribute_name)?;
for attribute in repetitive_attributes {
found_attributes.insert(attribute.name.to_owned(), attribute);
}
},
DataItemValueType::Compound { fspec:_, items } => {
let compound_attributes =
fill_compound_attributes(&category_prefix, &data_item_prefix, items, &mut frn_consumed_bits, &data_item_bits)?;
for attribute in compound_attributes {
found_attributes.insert(attribute.name.to_owned(), attribute);
}
},
DataItemValueType::Explicit { expl:_ } => (), },
}
}
Ok(found_attributes)
}
fn get_default_attribute_name(title: &str) -> String {
let default_name: String;
let temporary_name: String;
if title.len() > 30 {
let first_space_index = title.find(" ").unwrap_or(30_usize);
temporary_name = title[0..first_space_index].to_owned();
} else {
temporary_name = title.to_owned();
}
let re = Regex::new(r"[^a-zA-Z0-9_]").unwrap();
default_name = match re.replace_all(temporary_name.as_str(), "_") {
std::borrow::Cow::Borrowed(b) => b.to_owned().to_uppercase(),
std::borrow::Cow::Owned(o) => o.to_uppercase(),
};
default_name
}
fn fill_dataitem_element_attributes(
rule: &ElementType,
attribute: &mut Attribute) {
match rule {
ElementType::ContextFree { value } => match value {
ElementValueType::Fx => (),
ElementValueType::Integer { constraints:_, signed:_} => (),
ElementValueType::Quantity { constraints, lsb, signed, unit }
=> {
let mut found_constraints = Vec::<AttributeConstraint>::new();
for constraint in constraints {
let constraint_value = match constraint.value {
DataType::Integer { value } => value,
};
let attribute_constraint = AttributeConstraint {
constraint_type: constraint.constraint_type,
limit_value: AttributeConstraintLimit::SignedInteger { value: constraint_value }
};
found_constraints.push(attribute_constraint);
}
if found_constraints.len() > 0 {
attribute.constraints = Some(found_constraints);
}
attribute.signed = Some(*signed);
let lsb =
match lsb {
LsbType::Integer { value } => AttributeLsb::Integer { value: *value },
LsbType::Div { denominator, numerator } => {
let num = match numerator {
DataType::Integer { value } => *value as f64,
};
let den = match denominator {
DenominatorType::Pow { base, exponent } => {
base.powf(*exponent)
},
};
AttributeLsb::Real { value: num/den }
},
};
attribute.lsb = Some(lsb);
attribute.unit = Some(unit.to_owned());
match &attribute.lsb {
Some(l) => {
match l {
AttributeLsb::Integer { value } => {
let mut signed = false;
if attribute.signed.is_some() {
signed = match attribute.signed {
Some(b) => b,
None => false,
}
}
if signed {
let signed_value = attribute.bits.load::<i32>();
attribute.value_type = l.as_ref().to_owned();
attribute.stringfied_value = Some(format!("{}", *value * signed_value));
} else {
let unsigned_value = attribute.bits.load::<u32>();
attribute.value_type = l.as_ref().to_owned();
attribute.stringfied_value = Some(format!("{}", *value as u64 * unsigned_value as u64));
}
},
AttributeLsb::Real { value } => {
let mut signed = false;
if attribute.signed.is_some() {
signed = match attribute.signed {
Some(b) => b,
None => false,
}
}
if signed {
let attribute_value = attribute.bits.load::<i32>();
attribute.value_type = l.as_ref().to_owned();
attribute.stringfied_value = Some(format!("{:17.9}", *value * f64::from(attribute_value)));
} else {
let attribute_value = attribute.bits.load::<u32>();
attribute.value_type = l.as_ref().to_owned();
attribute.stringfied_value = Some(format!("{:17.9}", *value * f64::from(attribute_value)));
}
},
}
},
None => (),
}
},
ElementValueType::Raw => attribute.value_type = "Raw".to_owned(),
ElementValueType::Regular { size:_ } => attribute.value_type = "Regular".to_owned(),
ElementValueType::String { variation } => {
attribute.value_type = variation.to_string();
if attribute.value_type == "StringICAO" {
attribute.stringfied_value = convert_bits_to_icao_string(&attribute.bits);
}
},
ElementValueType::Table { values } => {
let attribute_value = attribute.bits.load::<u16>();
let converted_value = i32::from(attribute_value);
for vec_item in values {
if converted_value == vec_item.0{
attribute.stringfied_value = Some(vec_item.1.clone());
}
}
attribute.value_type = "Tabulated value".to_owned()
},
},
}
}
fn convert_bits_to_icao_string(bits: &BitVec<u8, Msb0>) -> Option<String> {
assert_eq!(0, bits.len()%6);
let mut string_icao = String::new();
let mut count = 0;
while count < bits.len() {
let char_bits = bits[count..count+6].to_bitvec();
let char_index = convert_bits_to_usize(&char_bits);
string_icao.push(crate::asterix::message::MAP_ICAO_CHARACTERS[char_index]);
println!("{}",char_index);
println!("{}",string_icao);
count += 6;
}
Some(string_icao)
}
fn convert_bits_to_usize(char_bits: &BitVec<u8, Msb0>) -> usize {
let mut ret:usize = 0;
ret += (if char_bits[0] { 1 } else { 0 }) * 0b100000;
ret += (if char_bits[1] { 1 } else { 0 }) * 0b10000;
ret += (if char_bits[2] { 1 } else { 0 }) * 0b1000;
ret += (if char_bits[3] { 1 } else { 0 }) * 0b100;
ret += (if char_bits[4] { 1 } else { 0 }) * 0b10;
ret += (if char_bits[5] { 1 } else { 0 }) * 0b1;
ret
}
fn fill_group_attributes(
category_prefix: &str,
data_item_prefix: &str,
items: &Vec<Option<AttributeItem>>,
frn_consumed_bits: &mut usize,
data_item_bits: BitVec<u8, Msb0>) -> anyhow::Result<Vec<Attribute>> {
let mut group_attributes = Vec::<Attribute>::new();
for item in items {
let inner_item = match item {
Some(e) => e,
None => continue,
};
match inner_item {
AttributeItem::SpareEntry { length, spare:_ } => {
*frn_consumed_bits += length;
continue
} ,
AttributeItem::AttributeEntry(v) => {
let mut attribute = Attribute::default();
attribute.name = format!("{}_{}_{}", category_prefix, data_item_prefix, v.name);
attribute.title = v.title.to_owned();
attribute.description = v.description.to_owned();
match &v.rule {
AttributeType::ContextFree { value } => match value {
AttributeValueType::Element { rule, size } => {
let start_bit = *frn_consumed_bits;
let last_bit = *frn_consumed_bits + *size as usize;
attribute.bits = data_item_bits[start_bit..last_bit].to_bitvec();
*frn_consumed_bits = last_bit;
fill_dataitem_element_attributes(rule, &mut attribute);
},
_ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())}
},
}
group_attributes.push(attribute);
},
};
}
Ok(group_attributes)
}
fn fill_extended_attributes(
category_prefix: &str,
data_item_prefix: &str,
items: &Vec<Option<AttributeItem>>,
frn_consumed_bits: &mut usize,
data_item_bits: BitVec<u8, Msb0>) -> anyhow::Result<Vec<Attribute>> {
let mut fx_set = true;
let mut extended_attributes = Vec::<Attribute>::new();
for item in items {
if !fx_set {
break
}
match item {
Some(i) => match i {
AttributeItem::SpareEntry { length, spare:_ } => *frn_consumed_bits += *length,
AttributeItem::AttributeEntry(a) => {
let mut attribute = Attribute::default();
attribute.name = format!("{}_{}_{}", category_prefix, data_item_prefix, a.name);
attribute.title = a.title.to_owned();
attribute.description = a.description.to_owned();
match &a.rule {
AttributeType::ContextFree { value }
=> match value {
AttributeValueType::Element { rule, size } => {
let start_bit = *frn_consumed_bits;
let last_bit = *frn_consumed_bits + *size as usize;
attribute.bits = data_item_bits[start_bit..last_bit].to_bitvec();
let bitslice = match data_item_bits.get(start_bit..last_bit) {
Some(b) => b,
_ => { return Err(ParseError::InvalidElementFieldLength { size: *size as usize }.into())}
};
let attribute_value = bitslice.load::<u16>();
let converted_value = i32::from(attribute_value);
*frn_consumed_bits = last_bit;
match rule {
ElementType::ContextFree { value } => {
match value {
ElementValueType::Table { values } => {
for vec_item in values {
if converted_value == vec_item.0{
attribute.stringfied_value = Some(vec_item.1.clone());
}
}
attribute.value_type = "Tabulated value".to_owned()
},
_ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())}
}
},
}
},
_ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())}
},
}
extended_attributes.push(attribute);
},
},
None => *frn_consumed_bits += 1,
}
if *frn_consumed_bits%8 == 0 {
let _bitstr = data_item_bits.to_string();
let fx_bit = data_item_bits[*frn_consumed_bits-1];
if !fx_bit {
fx_set = false;
}
}
}
Ok(extended_attributes)
}
fn fill_repetitive_attributes(
category_prefix: &str,
data_item_prefix: &str,
rep: &ElementValueType,
variation: &AttributeValueType,
frn_consumed_bits: &mut usize,
data_item_bits: BitVec<u8, Msb0>,
default_attribute_name: &String) -> anyhow::Result<Vec<Attribute>> {
let mut repetitive_attributes = Vec::<Attribute>::new();
let mut _multiplier: usize = 0;
let element_len: Option<usize>;
match rep {
ElementValueType::Fx => element_len = None,
ElementValueType::Regular { size } => {
let definition_size = usize::from(*size);
element_len = Some(definition_size);
let start_bit = *frn_consumed_bits;
let end_bit = start_bit + 8; let multiplier_bit_vec = data_item_bits[start_bit..end_bit].to_bitvec();
_multiplier = multiplier_bit_vec.load::<usize>();
assert_eq!(0, definition_size%8);
*frn_consumed_bits += 8;
},
_ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())},
};
let mut group_attributes: Vec<Attribute> = Vec::<Attribute>::new();
if element_len.is_some() {
match variation {
AttributeValueType::Group { items } => {
group_attributes.extend(
fill_group_attributes(category_prefix, data_item_prefix, items, &mut *frn_consumed_bits, data_item_bits)?);
},
_ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())},
};
let unique_group_attributes = ensure_no_repeated_attribute_names(&group_attributes)?;
repetitive_attributes.extend( unique_group_attributes);
} else {
match variation {
AttributeValueType::Element { rule, size }=> {
let repetitive_element_size = usize::from(*size);
match rule {
ElementType::ContextFree { value } => match value {
ElementValueType::Table { values } => {
let mut fx_bit = true; while fx_bit {
let mut attribute = Attribute::default();
attribute.name = format!("{}_{}_{}", category_prefix, data_item_prefix, default_attribute_name);
let start_bit = *frn_consumed_bits;
let end_bit = start_bit + repetitive_element_size;
let element_bit_vec = data_item_bits[start_bit..end_bit].to_bitvec();
*frn_consumed_bits += repetitive_element_size;
let element_value = element_bit_vec.load::<u16>();
let converted_value = element_value as i32;
fx_bit = data_item_bits[*frn_consumed_bits];
*frn_consumed_bits += 1;
for vec_item in values {
if converted_value == vec_item.0{
attribute.stringfied_value = Some(vec_item.1.clone());
}
}
attribute.value_type = "Tabulated value".to_owned();
repetitive_attributes.push(attribute);
}
},
_ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())},
},
}
},
_ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())},
};
}
let unique_group_attributes = ensure_no_repeated_attribute_names(&group_attributes)?;
repetitive_attributes.extend( unique_group_attributes);
Ok(repetitive_attributes)
}
fn fill_compound_attributes(
category_prefix: &str,
data_item_prefix: &str,
items: &[Option<AttributeItem>],
frn_consumed_bits: &mut usize,
data_item_bits: &BitVec<u8, Msb0>) -> anyhow::Result<Vec<Attribute>> {
let mut compound_attributes = Vec::<Attribute>::new();
let minimum_expected_frns = 7_u8;
let fspec_info: FSpecInfo = get_fspec_from_bits(data_item_bits.clone(), *frn_consumed_bits, minimum_expected_frns);
*frn_consumed_bits = usize::from(fspec_info.len)*8; let mut item_count = 1_u8;
for item in items {
if fspec_info.fspec[&item_count] == false {
item_count += 1;
continue;
}
match item {
Some(e) => {
match e {
AttributeItem::SpareEntry { length, spare:_ } => {
*frn_consumed_bits += length;
continue
},
AttributeItem::AttributeEntry(v) => {
let mut attribute = Attribute::default();
attribute.name = format!("{}_{}_{}", category_prefix, data_item_prefix, v.name);
attribute.title = v.title.to_owned();
attribute.description = v.description.to_owned();
match &v.rule {
AttributeType::ContextFree { value }
=> match value {
AttributeValueType::Element { rule, size } => {
let start_bit = *frn_consumed_bits;
let last_bit = *frn_consumed_bits + *size as usize;
attribute.bits = data_item_bits[start_bit..last_bit].to_bitvec();
*frn_consumed_bits = last_bit;
fill_dataitem_element_attributes(rule, &mut attribute);
compound_attributes.push(attribute);
item_count += 1;
},
AttributeValueType::Group { items }=> {
let compound_grouped_attributes =
fill_group_attributes(category_prefix, data_item_prefix, items,
frn_consumed_bits, data_item_bits.clone())?;
compound_attributes.extend(compound_grouped_attributes);
item_count += 1;
},
_ => { return Err(ParseError::ParserUnforeseenDependecyRelation.into())}
},
}
},
}
},
None => {
item_count += 1;
continue;
},
};
}
Ok(compound_attributes)
}
pub fn describe_message_attributes(message: BTreeMap<String, Attribute>) {
for attribute in message {
println!();
println!("key:[{}], bits length[{:02}] - bits:{}]", attribute.0, attribute.1.bits.len(), attribute.1.bits);
print!(" Title: {:?}", attribute.1.title);
if attribute.1.description.is_some()
{
print!(", description{:?}", attribute.1.description);
}
println!();
if attribute.1.signed.is_some() {
println!(" Signed: {}", attribute.1.signed.unwrap());
}
println!(" Type: {}", attribute.1.value_type);
if attribute.1.stringfied_value.is_some() {
println!(" Stringfied value: {}", attribute.1.stringfied_value.unwrap());
}
if attribute.1.unit.is_some() {
println!(" Unit: {}", attribute.1.unit.unwrap());
}
if attribute.1.constraints.is_some() {
match attribute.1.constraints {
Some(c) => {
for constraint in c {
let constraint_str =
match constraint.constraint_type {
ConstraintType::Less => { stringify!(ConstraintType::Less ) },
ConstraintType::Great => { stringify!(ConstraintType::Great ) },
ConstraintType::LessOrEqual => { stringify!(ConstraintType::LessOrEqual ) },
ConstraintType::GreatOrEqual => { stringify!(ConstraintType::GreatOrEqual ) },
};
let constraint_value =
match constraint.limit_value {
AttributeConstraintLimit::SignedInteger { value } => value.to_string(),
};
println!(" Constraint: {} {} ", constraint_str, constraint_value);
}
},
None => (),
}
}
if attribute.1.lsb.is_some() {
match attribute.1.lsb {
Some(e) => {
let lsb_value = match e {
AttributeLsb::Integer { value } => value.to_string(),
AttributeLsb::Real { value } => format!("{:15.7}", value),
};
println!(" LSB: {} ", lsb_value);
},
None => (),
}
}
}
}
fn ensure_no_repeated_attribute_names(
group_attributes: &Vec<Attribute>) -> anyhow::Result<Vec<Attribute>> {
let mut unique_group_attributes = Vec::<Attribute>::new();
let mut attr_name_vec = Vec::<(String, usize)>::new();
for attr in group_attributes {
let mut new_attr = attr.clone();
match attr_name_vec.clone()
.into_iter()
.find(|x| x.0 == attr.name) {
Some(x_attr) => {
let mut counter = x_attr.1;
counter += 1;
let x = attr_name_vec.iter().position(|x| *x == x_attr);
let index = match x {
Some(i) => i,
None => return Err(ParseError::ParserUnforeseenDependecyRelation.into()),
};
attr_name_vec.remove(index);
new_attr.name = format!("{}_{}", attr.name, counter);
attr_name_vec.push((attr.name.clone(), counter));
unique_group_attributes.push(new_attr);
},
None => {
attr_name_vec.push((attr.name.clone(), 0_usize ));
unique_group_attributes.push(attr.clone());
},
};
}
Ok(unique_group_attributes)
}
#[cfg(test)]
pub mod tests {
use crate::asterix::uap_json::structures::Attribute;
use super::ensure_no_repeated_attribute_names;
#[test]
fn ut_test_repeated_attributs_are_resolved() -> anyhow::Result<()> {
let mut group_attributes = Vec::<crate::asterix::uap_json::structures::Attribute>::new();
let mut attr1 = Attribute::default();
let mut attr2 = Attribute::default();
let mut attr3 = Attribute::default();
let mut attr4 = Attribute::default();
attr1.name = "ATTR".to_owned();
attr2.name = "ATTR".to_owned();
attr3.name = "SOME".to_owned();
attr4.name = "ATTR".to_owned();
group_attributes.push(attr1);
group_attributes.push(attr2);
group_attributes.push(attr3);
group_attributes.push(attr4);
let unique_attributes = ensure_no_repeated_attribute_names(&group_attributes)?;
assert_eq!(4, unique_attributes.len());
assert_eq!("ATTR".to_owned(), unique_attributes[0].name);
assert_eq!("ATTR_1".to_owned(), unique_attributes[1].name);
assert_eq!("SOME".to_owned(), unique_attributes[2].name);
assert_eq!("ATTR_2".to_owned(), unique_attributes[3].name);
Ok(())
}
}