asterix_parser 0.1.1

Playground do Protocolo ASTERIX
Documentation
pub mod category;
pub mod message;
pub mod uap;
pub mod uap_json;

use std::collections::BTreeMap;
use std::fs;
use thiserror::Error;

use self::category::{Category, CategoryIndex, CategoryKey};
use self::uap::providers::Provider;
use self::uap_json::errors::ParseError;
use self::uap_json::loader::Loader;
use self::uap_json::structures::{DataRecord, Edition};

#[derive(Error, Debug)]
pub enum ContextErrors {
    #[error("Definition folder for UAPs could not be loaded")]
    UAPDefinitionFolderCouldNotBeLoaded,
    #[error("unknown error")]
    Unknown,
}

/// A data block is blocking mechanism may be used to combine several Data Records in an ASTERIX Data Block.
/// 
/// An ASTERIX Data Block shall consist of:
///     • a one-octet Data [Category] (CAT) field, indicating the ASTERIX Category;
///     • a two-octet Length Indicator (LEN) field, indicating the total length (in octets) of the ASTERIX
///       Data Block, including the CAT and LEN fields;
/// 
/// Each [Data Record](DataRecord) is of variable length but aligned on an octet boundary.
/// The length of an ASTERIX Data Block is thus variable but shall always be a multiple of an octet.
/// The maximum size of an ASTERIX Data Block shall be mutually agreed between data sources and
/// users. Because of the size of the Length Indicator the maximum possible length of an ASTERIX Data
/// Block is 65.535 octets.
/// (from document:  [EUROCONTROL-SPEC-0149](https://www.eurocontrol.int/asterix))
/// 
pub struct DataBlock {
    pub records: Vec<DataRecord>
}

type CategoryMap = BTreeMap<CategoryKey, Category>;
type UapMap = BTreeMap<CategoryKey, DataRecord>;

pub struct Context {
    // pub uap_definitions: UAPDefinitions,
    pub categories: CategoryMap,
    pub uap_definitions: UapMap
}

impl Context {
    const UAPS_FOLDER: &'static str = "./resources/uaps";

    pub fn new() -> anyhow::Result<Context> {
        let (categories, uap_defs) = Context::load()?;

        Ok(Context { 
            categories: categories,
            uap_definitions: uap_defs
        })
    }

    fn find_uap_definition_files() -> anyhow::Result<Vec<String>> {
        let uap_files = match fs::read_dir(Context::UAPS_FOLDER) {
            Ok(read_dir) => {
                let mut files = Vec::<String>::new();
                for result in read_dir {
                    let path = match result {
                        Ok(dir_entry) =>  {
                            let filename = 
                                match dir_entry.file_name().into_string() {
                                    Ok(s) => s,
                                    Err(_) => { return Err(ContextErrors::UAPDefinitionFolderCouldNotBeLoaded.into()); },
                                };
                            
                            filename
                        },
                        Err(e) => { return Err(e.into()); },
                    };
                    files.push(path);
                };
                files
            },
            Err(e) => { return Err(e.into()); },
        };
        
        /* for file in &uap_files {
            println!("Loading file {}", file);
        } */
    
        Ok(uap_files)
    }
    
    fn load() -> anyhow::Result<(CategoryMap, UapMap)> {
        let mut categories = CategoryMap::new();
        let mut uap_defs = UapMap::new();

        let uap_files = Context::find_uap_definition_files()?;
        for file in uap_files {
            let filepath_and_name = format!("{}/{}", Context::UAPS_FOLDER, file);
            let uap_definition = Loader::load(&filepath_and_name)?;
            let category_index = 
                match CategoryIndex::from_u8(uap_definition.number) {
                    Some(i) => i,
                    None => { return Err(ParseError::OpenUapJsonDefinitionError.into()) }
                };
           
            let category = 
                Category::new(
                    CategoryKey {
                        index: category_index, 
                        edition: uap_definition.edition.clone(),
                        provider: Provider::Standard
                    },
                    uap_definition.title.as_str());

            categories.insert(category.key.clone(), category.clone());
            uap_defs.insert(category.key, uap_definition);
        }

        Ok((categories, uap_defs))
    }    

    pub fn find_definition(&self, category_key: CategoryKey) -> anyhow::Result<DataRecord> {
        let mut uap_def_opt: Option<DataRecord> = None;

        for uap in &self.uap_definitions {
            if uap.0 == &category_key {
                uap_def_opt = Some(uap.1.clone())
            }
        }

        if uap_def_opt.is_none() {
            return Err(ParseError::CategoryNotYetSupported { 
                category_code: format!("{}", category_key.index.as_string()),
                edition: format!("{}.{}", category_key.edition.major, category_key.edition.minor),
                provider: category_key.provider.as_ref().to_owned(),
             }.into());
        }

        Ok(uap_def_opt.unwrap())
   }
   
    fn find_newest_edition_for_category(&self, cat_idx: &CategoryIndex) -> anyhow::Result<Edition> {
        let uap_defs:&Vec<&CategoryKey> = &self.uap_definitions
            .keys()
                .into_iter()
                    .filter(|x| x.index == *cat_idx).collect::<Vec<&CategoryKey>>();

        if uap_defs.is_empty() {
            return Err(ParseError::CategoryUapDefinitionNotFound { category_code: cat_idx.as_string()}.into());
        }

        let uap_def = *uap_defs.into_iter().max().unwrap();

        Ok(uap_def.edition.clone())
    }


}