diff --git a/Cargo.lock b/Cargo.lock index 2e89602..d1e4a83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -379,6 +379,13 @@ dependencies = [ "serde", ] +[[package]] +name = "nastester" +version = "0.1.0" +dependencies = [ + "f06", +] + [[package]] name = "num" version = "0.4.1" diff --git a/Cargo.toml b/Cargo.toml index 5f9fe10..1a108dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,4 @@ members = [ "f06", "f06info", "f06diff" -, "nas_csv", "f06csv"] +, "nas_csv", "f06csv", "nastester"] diff --git a/f06/src/blocks/indexing.rs b/f06/src/blocks/indexing.rs index ad3a974..9cc1cb4 100644 --- a/f06/src/blocks/indexing.rs +++ b/f06/src/blocks/indexing.rs @@ -120,9 +120,30 @@ macro_rules! gen_nasindex { }; } } + + impl NasIndex { + /// Returns the name of the type of this index. + pub fn type_name(&self) -> &'static str { + return match self { + $(Self::$tn(_) => <$tn as IndexType>::INDEX_NAME,)* + }; + } + } }; } +impl NasIndex { + /// Returns the grid point associated with this index, if it has one. + pub fn grid_point_id(&self) -> Option { + todo!() + } + + /// Returns the element associated with this index, if it has one. + pub fn element_id(&self) -> Option { + todo!() + } +} + gen_nasindex!( Dof, GridPointRef, diff --git a/f06/src/f06file.rs b/f06/src/f06file.rs index d77ed7b..cc6140c 100644 --- a/f06/src/f06file.rs +++ b/f06/src/f06file.rs @@ -2,6 +2,7 @@ //! it, and its submodules are responsible for specific parsing subroutines. pub mod diff; +pub mod extraction; use std::collections::{BTreeSet, BTreeMap}; diff --git a/f06/src/f06file/extraction.rs b/f06/src/f06file/extraction.rs new file mode 100644 index 0000000..d91af73 --- /dev/null +++ b/f06/src/f06file/extraction.rs @@ -0,0 +1,175 @@ +//! This module implements data structures to specify ways to extract data +//! subsets from F06 files. + +use std::error::Error; +use std::fmt::Display; +use std::mem::discriminant; + +use serde::{Deserialize, Serialize}; + +use crate::prelude::*; + +/// This specifies a value or sets thereof. +#[derive( + Debug, Clone, Serialize, Deserialize, PartialOrd, Ord, PartialEq, Eq +)] +pub enum Specifier { + /// Use all in the file. + All, + /// Use a list. + List(Vec), + /// Use an exclusion list. + AllExcept(Vec) +} + +impl Specifier { + /// Use this as a filter for an iterator. + fn filter_fn(&self, item: &A) -> bool { + return match self { + Self::All => true, + Self::List(l) => l.contains(item), + Self::AllExcept(l) => !l.contains(item), + }; + } +} + +/// This is a "full index", it refers to a single datum in an F06 file. +#[derive( + Debug, Copy, Clone, Serialize, Deserialize, PartialOrd, Ord, PartialEq, Eq +)] +pub struct DatumIndex { + /// The block reference. + pub block_ref: BlockRef, + /// The row. + pub row: NasIndex, + /// The column. + pub col: NasIndex +} + +impl DatumIndex { + /// Attempts to get the value at this index from a data block. + pub fn get_from( + &self, + file: &F06File + ) -> Result { + let block = file.block_search( + Some(self.block_ref.block_type), + Some(self.block_ref.subcase), + true + ).nth(0).ok_or(ExtractionError::NoSuchBlock(self.block_ref))?; + let ri_ex = block.row_indexes.keys().nth(0) + .ok_or(ExtractionError::BlockIsEmpty)?; + let ci_ex = block.col_indexes.keys().nth(0) + .ok_or(ExtractionError::BlockIsEmpty)?; + if discriminant(&self.row) != discriminant(ri_ex) { + return Err(ExtractionError::RowTypeMismatch { + tried: self.row, + against: *ri_ex + }); + } + if discriminant(&self.col) != discriminant(ci_ex) { + return Err(ExtractionError::ColumnTypeMismatch { + tried: self.col, + against: *ci_ex + }); + } + if !block.row_indexes.contains_key(&self.row) { + return Err(ExtractionError::MissingRow(self.row)); + } + if !block.col_indexes.contains_key(&self.col) { + return Err(ExtractionError::MissingColumn(self.col)); + } + return Ok(block.get(self.row, self.col).expect("row & col check failed!")); + } +} + +/// This is the kind of error that can be returned when extracting a datum. +#[derive( + Debug, Copy, Clone, Serialize, Deserialize +)] +pub enum ExtractionError { + /// The F06 file has no block matching a subcase and type. + NoSuchBlock(BlockRef), + /// The block was found but there was an index type mismatch for the rows. + RowTypeMismatch { + /// A row index we tried to use. + tried: NasIndex, + /// An example of row index from the block. + against: NasIndex + }, + /// The block was found but there was an index type mismatch for the columns. + ColumnTypeMismatch { + /// A column index we tried to use. + tried: NasIndex, + /// An example of column index from the block. + against: NasIndex + }, + /// A row index is the correct type but is not part of the matrix. + MissingRow(NasIndex), + /// A column index is the correct type but is not part of the matrix. + MissingColumn(NasIndex), + /// The block has no data. + BlockIsEmpty +} + +impl Display for ExtractionError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + return match self { + Self::NoSuchBlock(bref) => write!( + f, + "no such block ({}, subcase {})", + bref.block_type.short_name(), + bref.subcase + ), + Self::RowTypeMismatch { tried, against } => write!( + f, + "wrong row type (tried a {}, block uses {})", + tried.type_name(), + against.type_name() + ), + Self::ColumnTypeMismatch { tried, against } => write!( + f, + "wrong column type (tried a {}, block uses {})", + tried.type_name(), + against.type_name() + ), + Self::MissingRow(ri) => write!(f, "no such row ({})", ri), + Self::MissingColumn(ci) => write!(f, "no such column ({})", ci), + Self::BlockIsEmpty => write!(f, "block is empty") + }; + } +} + +impl Error for ExtractionError {} + +/// This structure represents a way to extract a subset of the data from an F06 +/// so one can apply comparison criteria to it. +#[derive( + Debug, Clone, Serialize, Deserialize, PartialOrd, Ord, PartialEq, Eq +)] +pub struct Extraction { + /// Subcases to get data from. + subcases: Specifier, + /// Block types to get data from. + blocks: Specifier, + /// Grid point filter (filters out grid points if present). + grid_points: Specifier, + /// Element filter (filters out element IDs if present). + elements: Specifier, + /// Row filter (for when you want very specific data). + rows: Specifier, + /// Column filter (for when you want very specific data). + cols: Specifier +} + +impl Extraction { + /// Produces an iterator over the indices resulting from applying an + /// extraction to a file. This assumes the file has already had its blocks + /// sorted and merged. + pub fn lookup( + &self, + file: &F06File + ) -> impl Iterator + '_ { + todo!() + } +} diff --git a/f06csv/src/main.rs b/f06csv/src/main.rs index 308154d..c6ce916 100644 --- a/f06csv/src/main.rs +++ b/f06csv/src/main.rs @@ -145,7 +145,7 @@ fn main() -> Result<(), Box> { .terminator(term) .from_writer(output); /// Filter only if there is at least one in the filter. - fn lax_filter(v: &Vec, x: &Option) -> bool { + fn lax_filter(v: &[T], x: &Option) -> bool { return v.is_empty() || x.is_none() || x.as_ref().is_some_and(|k| v.contains(k)); diff --git a/nastester/Cargo.toml b/nastester/Cargo.toml new file mode 100644 index 0000000..67e94ba --- /dev/null +++ b/nastester/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "nastester" +authors = ["Bruno Borges Paschoalinoto "] +version = "0.1.0" +edition = "2021" + +[dependencies] + + +[dependencies.f06] +version = "0.3" +path = "../f06" diff --git a/nastester/src/main.rs b/nastester/src/main.rs new file mode 100644 index 0000000..80a1832 --- /dev/null +++ b/nastester/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}