asterix_parser 0.1.1

Playground do Protocolo ASTERIX
Documentation
pub mod cat048;
pub mod parser;

use std::collections::BTreeMap;

use custom_error::custom_error;

use crate::asterix::uap::common::dataitems::DataItemIndex;
use crate::asterix::uap::providers::Provider;
use crate::asterix::uap::UAPDataItem;
use crate::asterix::uap::common::dataitems::DataItem;
use crate::asterix::uap::common::dataitems::get_lsb_bits;
use crate::asterix::category::CategoryIndex;

use self::constants::*;

use super::uap_json::structures::Attribute;

pub mod constants {
    /// Start of message
    pub const MESSAGE_CAT_OCTET_INDEX: usize = 0;
    /// Start of length of message octets, composed of 2 octets
    pub const MESSAGE_LEN_OCTET_INDEX: usize = 1;
    /// Start of record fspec octets
    pub const MESSAGE_FSPEC_OCTET_START_INDEX: usize = 3;

    pub const MAP_ICAO_CHARACTERS: &'static [char] = &[   
        '#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
        'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
        'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '#', '#', '#',
        '#', '#', ' ', '#', '#', '#', '#', '#', '#', '#',
        '#', '#', '#', '#', '#', '#', '#', '#', '0', '1',
        '2', '3', '4', '5', '6', '7', '8', '9', '#', '#',
        '#', '#', '#', '#'];
}

pub struct MessageDataItem {
    pub frn: u8,
    pub presence: bool,
    pub data_item: DataItem,
    // todo: possible store of octets that compose that data item
    // pub octets_content: Vec<u8>,
}

custom_error!{ pub AsterixMessageParseError
    InvalidCategory{category: u8, provider: Provider}        = "CAT {category} for provider {provider} is not yet implemented",
    InvalidLength{provided_len: usize, stream_len: usize }   = "The provided messsage length [{provided_len}] does not comply with message stream length [{stream_len}]",
    InvalidRepetitiveFieldLength{size: usize}                = "The provided reptitive field length is invalid [{size}]",
    CouldNotRetrieveLength{dataitem: String}                 = "The provided data item [{dataitem}] could not return a valid length",
    OtherError                                               = "Some other error has occurred"
}

pub struct AsterixMessage {
    pub code: String,
    pub description: String,
    pub provider: String, /*
    pub data_items_store: BTreeMap<u8, MessageDataItem>, */
    pub attributes_map: BTreeMap<String, Attribute>
}

impl AsterixMessage {
    pub fn new(
        code: String, 
        description: String, 
        provider: String, /* 
        data_items_store: BTreeMap<u8, MessageDataItem>, */ 
        attributes: BTreeMap<String, Attribute>) -> Self {
        Self { code, description, provider, /* data_items_store,*/ attributes_map: attributes }
    }
     
    fn _get_message_data_items(message_octets: &Vec<u8>, uap_data_items: Vec<UAPDataItem>) -> (usize, Vec<MessageDataItem>) {
        let mut message_data_items = Vec::<MessageDataItem>::new();
        let mut data_start_index = MESSAGE_FSPEC_OCTET_START_INDEX + 1;
        let mut octet_index: usize = MESSAGE_FSPEC_OCTET_START_INDEX;
        let mut data_item_index = 1;

        for data_item in uap_data_items {
            let message_data_item = MessageDataItem {
                presence: false,
                frn: data_item.frn,
                data_item: data_item.data_item
            };

            message_data_items.push(message_data_item);
        }

        let mut has_more_fspec = true;
        while has_more_fspec == true {
            let fspec = message_octets[octet_index];

            let fspec_bits = get_lsb_bits(&[fspec]);
            has_more_fspec = fspec_bits[7]; // fspec fx bit
            (1..9 as usize).for_each(|i| {
                let fspec_item_index = 8-i;
                let is_present =  fspec_bits[fspec_item_index];

                if i == 8 { // reached one fspec fx bit
                    if !is_present {
                        // FX bit indicates no more fspecs are set
                        has_more_fspec = false;
                    } else { 
                        octet_index += 1; // last item of fspec reached, advance to the next octed
                        data_start_index += 1; // increment data start position, since we have one more fspec
                    }
                }
                else {
                    message_data_items[data_item_index-1].presence = is_present;
                    data_item_index = data_item_index + 1; // increment frn index
                }
            });
        }

        return (data_start_index, message_data_items);
    }
    
    /*
    pub fn check_message_can_be_parsed(message_octets: &Vec<u8>, provider: Provider, context: &Context) 
        -> Result<UAPDefinition, AsterixMessageParseError> {

        let category_index = match CategoryIndex::from_u8(message_octets[MESSAGE_CAT_OCTET_INDEX]) {
            Some(c) => c,
            None => {
                let cat = message_octets[MESSAGE_CAT_OCTET_INDEX];
                return Err(AsterixMessageParseError::InvalidCategory { category: cat, provider: provider })
            }
        };

        // Check stream length against provided length from message
        let provided_len  = (((message_octets[1] as u16) * 256) + message_octets[2] as u16) as usize;
        match &message_octets.len() == &provided_len {
            true => (),
            false => return Err(AsterixMessageParseError::InvalidLength { provided_len, stream_len: message_octets.len() }),
        }

        let uap_msg_definition = match context.uap_definitions.find_definition(&category_index, &provider) {
            Some(uap_definition) => uap_definition,
            None => { 
                return Err(AsterixMessageParseError::InvalidCategory { category: category_index.as_u8(), provider: provider })
            },
        };

        Ok(uap_msg_definition.clone())
    } */
    
}

fn _assert_uap_items_presence(uap_definition: &Vec<MessageDataItem>) {
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_010, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_140, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_020, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_040, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_070, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_090, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_130, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_220, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_240, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_250, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_161, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_042, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_200, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_170, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_210, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_030, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_080, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_100, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_110, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_120, uap_definition));
    assert_eq!(true,  _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_230, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_260, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_055, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_050, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_065, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_060, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_SPF, uap_definition));
    assert_eq!(false, _find_data_item_presence(CategoryIndex::_048, DataItemIndex::_REF, uap_definition));
}

fn _find_data_item_presence(category_index: CategoryIndex, data_item_index: DataItemIndex, uap_definition: &Vec<MessageDataItem>) -> bool {
    let uap_data_item
        = uap_definition.into_iter()
                        .find(|x| 
                                   x.data_item.category == category_index &&
                                   x.data_item.data_item_index == data_item_index).unwrap() ;
    return uap_data_item.presence;                        
}