mod dimension;
pub(crate) use dimension::DimensionSize;
pub use dimension::{Dimension, DimensionType};
mod attribute;
pub use attribute::Attribute;
mod variable;
pub use variable::Variable;
mod tests;
use std::{cell::RefMut, ops::Deref, rc::Rc};
use crate::data_vector::DataVector;
use crate::{DataType, InvalidDataSet};
pub const NC_FILL_I8: i8 = -127;
pub const NC_FILL_U8: u8 = 0;
pub const NC_FILL_I16: i16 = -32767;
pub const NC_FILL_I32: i32 = -2147483647;
#[allow(clippy::excessive_precision)]
pub const NC_FILL_F32: f32 = 9.9692099683868690e+36;
#[allow(clippy::excessive_precision)]
pub const NC_FILL_F64: f64 = 9.9692099683868690e+36;
pub const NC_MAX_DIM_SIZE: usize = (i32::MAX - 3) as usize;
pub const NC_MAX_VAR_DIMS: usize = 1024;
#[derive(Debug, PartialEq)]
pub struct DataSet {
pub(crate) unlimited_dim: Option<Rc<Dimension>>,
pub(crate) dims: Vec<Rc<Dimension>>,
pub(crate) attrs: Vec<Attribute>,
pub(crate) vars: Vec<Variable>,
}
impl Default for DataSet {
fn default() -> Self {
Self::new()
}
}
impl DataSet {
pub fn new() -> DataSet {
DataSet {
unlimited_dim: None,
dims: vec![],
attrs: vec![],
vars: vec![],
}
}
pub fn add_fixed_dim<T: std::convert::AsRef<str>>(
&mut self,
dim_name: T,
dim_size: usize,
) -> Result<(), InvalidDataSet> {
let dim_name: &str = dim_name.as_ref();
if self.dims.iter().any(|dim| *dim.name.borrow() == dim_name) {
return Err(InvalidDataSet::DimensionAlreadyExists(dim_name.to_string()));
}
let new_fixed_size_dim = Rc::new(Dimension::new_fixed_size(dim_name, dim_size)?);
self.dims.push(new_fixed_size_dim);
Ok(())
}
pub fn set_unlimited_dim<T: std::convert::AsRef<str>>(
&mut self,
dim_name: T,
dim_size: usize,
) -> Result<(), InvalidDataSet> {
let dim_name: &str = dim_name.as_ref();
if let Some(unlimited_dim) = &self.unlimited_dim {
return Err(InvalidDataSet::UnlimitedDimensionAlreadyExists(
unlimited_dim.name(),
));
}
if self.dims.iter().any(|dim| *dim.name.borrow() == dim_name) {
return Err(InvalidDataSet::DimensionAlreadyExists(dim_name.to_string()));
}
let new_unlimited_dim = Rc::new(Dimension::new_unlimited_size(dim_name, dim_size)?);
self.dims.push(Rc::clone(&new_unlimited_dim));
self.unlimited_dim = Some(new_unlimited_dim);
Ok(())
}
pub fn num_dims(&self) -> usize {
self.dims.len()
}
pub fn has_dim(&self, dim_name: &str) -> bool {
self.find_dim_from_name(dim_name).is_some()
}
pub fn get_dim(&self, dim_name: &str) -> Option<Rc<Dimension>> {
self.find_dim_from_name(dim_name)
.map(|(_dim_index, dim): (usize, &Rc<Dimension>)| Rc::clone(dim))
}
pub fn get_dims(&self) -> Vec<Rc<Dimension>> {
self.dims
.iter()
.map(|dim: &Rc<Dimension>| Rc::clone(dim))
.collect()
}
pub fn dim_names(&self) -> Vec<String> {
self.dims.iter().map(|dim| dim.name().to_string()).collect()
}
pub fn has_unlimited_dim(&self) -> bool {
self.unlimited_dim.is_some()
}
pub fn get_unlimited_dim(&self) -> Option<Rc<Dimension>> {
self.unlimited_dim
.as_ref()
.map(|rc_dim: &Rc<Dimension>| Rc::clone(rc_dim))
}
pub fn dim_size(&self, dim_name: &str) -> Option<usize> {
self.find_dim_from_name(dim_name)
.map(|(_dim_index, dim)| dim.size())
}
pub fn dim_type(&self, dim_name: &str) -> Option<DimensionType> {
self.find_dim_from_name(dim_name)
.map(|(_dim_index, dim)| dim.dim_type())
}
pub fn remove_dim(&mut self, dim_name: &str) -> Result<Rc<Dimension>, InvalidDataSet> {
let removed_dim_index: usize = match self.find_dim_from_name(dim_name) {
None => {
return Err(InvalidDataSet::DimensionNotDefined(dim_name.to_string()));
}
Some((index, _)) => index,
};
let mut variables_using_removed_dim: Vec<String> = vec![];
for current_var in self.vars.iter() {
if current_var.use_dim(dim_name) {
variables_using_removed_dim.push(current_var.name.clone());
}
}
if !variables_using_removed_dim.is_empty() {
return Err(InvalidDataSet::DimensionYetUsed {
var_names: variables_using_removed_dim,
dim_name: dim_name.to_string(),
});
}
let removed_dim: Rc<Dimension> = self.dims.remove(removed_dim_index);
if removed_dim.is_unlimited() {
self.unlimited_dim = None;
}
Ok(removed_dim)
}
pub fn rename_dim(
&mut self,
old_dim_name: &str,
new_dim_name: &str,
) -> Result<(), InvalidDataSet> {
if old_dim_name == new_dim_name {
return Ok(());
}
let (_dim_position, renamed_dim): (usize, &Rc<Dimension>) =
match self.find_dim_from_name(old_dim_name) {
None => {
return Err(InvalidDataSet::DimensionNotDefined(
old_dim_name.to_string(),
));
}
Some(rc_dim) => rc_dim,
};
if self.find_dim_from_name(new_dim_name).is_some() {
return Err(InvalidDataSet::DimensionAlreadyExists(
new_dim_name.to_string(),
));
}
Dimension::check_dim_name(new_dim_name)?;
let mut dim_name: RefMut<String> = renamed_dim.name.borrow_mut();
*dim_name = new_dim_name.to_string();
Ok(())
}
fn find_dim_from_name(&self, dim_name: &str) -> Option<(usize, &Rc<Dimension>)> {
self.dims
.iter()
.position(|dim| {
return dim.name.borrow().deref() == dim_name;
})
.map(|index| (index, &self.dims[index]))
}
pub fn get_dims_from_dim_ids(
&self,
dim_ids: &[usize],
) -> Result<Vec<Rc<Dimension>>, InvalidDataSet> {
let searched_dim_ids = dim_ids;
let not_found_dim_ids: Vec<usize> = dim_ids
.iter()
.filter(|dim_id: &&usize| self.dims.get(**dim_id).is_none())
.copied()
.collect();
if !not_found_dim_ids.is_empty() {
return Err(InvalidDataSet::DimensionIdsNotFound {
defined: (0..self.dims.len()).collect(),
searched: searched_dim_ids.to_vec(),
not_found: not_found_dim_ids,
});
}
Ok(dim_ids
.iter()
.map(|dim_id: &usize| Rc::clone(&self.dims[*dim_id]))
.collect())
}
pub(crate) fn get_var_dim_ids(&self, var_name: &str) -> Option<Vec<usize>> {
let var: &Variable = self.find_var_from_name(var_name).ok()?.1;
let var_dims: &[Rc<Dimension>] = &var.dims;
let var_dim_ids: Vec<usize> = var_dims.iter().map(|var_dim: &Rc<Dimension>| {
self.dims.iter()
.position(|data_set_dim: &Rc<Dimension>| Rc::ptr_eq(data_set_dim, var_dim))
.expect("Shouldn't have occurred! All variable dimensions are defined in the data set, their positions should have been found.")
}).collect();
Some(var_dim_ids)
}
pub fn add_var<T: std::convert::AsRef<str>>(
&mut self,
var_name: &str,
dims_name: &[T],
data_type: DataType,
) -> Result<(), InvalidDataSet> {
let var_dims: Vec<&Rc<Dimension>> = {
let mut var_dims: Vec<&Rc<Dimension>> = vec![];
let mut undefined_dims: Vec<String> = vec![];
for dim_name in dims_name.iter() {
let dim_name: &str = dim_name.as_ref();
match self.find_dim_from_name(dim_name) {
None => {
undefined_dims.push(dim_name.to_string());
}
Some((_index, dim)) => {
var_dims.push(dim);
}
}
}
if !undefined_dims.is_empty() {
return Err(InvalidDataSet::DimensionsNotDefined {
var_name: var_name.to_string(),
undef_dim_names: undefined_dims,
});
}
var_dims
};
if self.find_var_from_name(var_name).is_ok() {
return Err(InvalidDataSet::VariableAlreadyExists(var_name.to_string()));
}
let var_dims: Vec<Rc<Dimension>> = var_dims.into_iter().map(Rc::clone).collect();
self.add_var_using_dim_refs(var_name, var_dims, data_type.clone())?;
Ok(())
}
pub(crate) fn add_var_using_dim_refs(
&mut self,
var_name: &str,
var_dims: Vec<Rc<Dimension>>,
data_type: DataType,
) -> Result<&Variable, InvalidDataSet> {
self.vars
.push(Variable::new(var_name, var_dims, data_type)?);
Ok(self.vars.last().unwrap())
}
pub fn add_var_i8<T: std::convert::AsRef<str>>(
&mut self,
var_name: &str,
dims_name: &[T],
) -> Result<(), InvalidDataSet> {
self.add_var(var_name, dims_name, DataType::I8)
}
pub fn add_var_u8<T: std::convert::AsRef<str>>(
&mut self,
var_name: &str,
dims_name: &[T],
) -> Result<(), InvalidDataSet> {
self.add_var(var_name, dims_name, DataType::U8)
}
pub fn add_var_i16<T: std::convert::AsRef<str>>(
&mut self,
var_name: &str,
dims_name: &[T],
) -> Result<(), InvalidDataSet> {
self.add_var(var_name, dims_name, DataType::I16)
}
pub fn add_var_i32<T: std::convert::AsRef<str>>(
&mut self,
var_name: &str,
dims_name: &[T],
) -> Result<(), InvalidDataSet> {
self.add_var(var_name, dims_name, DataType::I32)
}
pub fn add_var_f32<T: std::convert::AsRef<str>>(
&mut self,
var_name: &str,
dims_name: &[T],
) -> Result<(), InvalidDataSet> {
self.add_var(var_name, dims_name, DataType::F32)
}
pub fn add_var_f64<T: std::convert::AsRef<str>>(
&mut self,
var_name: &str,
dims_name: &[T],
) -> Result<(), InvalidDataSet> {
self.add_var(var_name, dims_name, DataType::F64)
}
pub fn num_vars(&self) -> usize {
self.vars.len()
}
pub fn has_var(&self, var_name: &str) -> bool {
self.find_var_from_name(var_name).is_ok()
}
pub fn is_record_var(&self, var_name: &str) -> Option<bool> {
self.find_var_from_name(var_name)
.map(|(_var_index, var): (usize, &Variable)| var.is_record_var())
.ok()
}
pub fn var_len(&self, var_name: &str) -> Option<usize> {
self.find_var_from_name(var_name)
.map(|(_var_index, var): (usize, &Variable)| var.len())
.ok()
}
pub fn var_data_type(&self, var_name: &str) -> Option<DataType> {
self.find_var_from_name(var_name)
.map(|(_var_index, var): (usize, &Variable)| var.data_type())
.ok()
}
pub fn get_var(&self, var_name: &str) -> Option<&Variable> {
self.find_var_from_name(var_name)
.map(|(_var_index, var): (usize, &Variable)| var)
.ok()
}
pub fn get_var_mut(&mut self, var_name: &str) -> Option<&mut Variable> {
self.find_var_from_name(var_name)
.map(|(var_index, _ref_var)| var_index)
.map(move |var_index: usize| &mut self.vars[var_index])
.ok()
}
pub fn get_vars(&self) -> Vec<&Variable> {
self.vars.iter().collect()
}
pub fn get_var_names(&self) -> Vec<String> {
self.vars
.iter()
.map(|var: &Variable| var.name().to_string())
.collect()
}
pub fn rename_var(
&mut self,
old_var_name: &str,
new_var_name: &str,
) -> Result<(), InvalidDataSet> {
if old_var_name == new_var_name {
return Ok(());
}
let renamed_var_index: usize = self.find_var_from_name(old_var_name)?.0;
if self.find_var_from_name(new_var_name).is_ok() {
return Err(InvalidDataSet::VariableAlreadyExists(
new_var_name.to_string(),
));
}
Variable::check_var_name(new_var_name)?;
self.vars[renamed_var_index].name = new_var_name.to_string();
Ok(())
}
pub fn remove_var(&mut self, var_name: &str) -> Result<Variable, InvalidDataSet> {
let var_index: usize = self.find_var_from_name(var_name)?.0;
let removed_var: Variable = self.vars.remove(var_index);
Ok(removed_var)
}
pub(crate) fn find_var_from_name(
&self,
var_name: &str,
) -> Result<(usize, &Variable), InvalidDataSet> {
self.vars
.iter()
.position(|var: &Variable| var.name == var_name)
.map(|var_index| (var_index, &self.vars[var_index]))
.ok_or(InvalidDataSet::VariableNotDefined(var_name.to_string()))
}
pub fn add_var_attr_i8(
&mut self,
var_name: &str,
attr_name: &str,
var_attr_value: Vec<i8>,
) -> Result<(), InvalidDataSet> {
let var_index: usize = self.find_var_from_name(var_name)?.0;
let var: &mut Variable = &mut self.vars[var_index];
var.add_attr_i8(attr_name, var_attr_value)?;
Ok(())
}
pub fn add_var_attr_u8(
&mut self,
var_name: &str,
attr_name: &str,
var_attr_value: Vec<u8>,
) -> Result<(), InvalidDataSet> {
let var_index: usize = self.find_var_from_name(var_name)?.0;
let var: &mut Variable = &mut self.vars[var_index];
var.add_attr_u8(attr_name, var_attr_value)?;
Ok(())
}
pub fn add_var_attr_string<T: AsRef<str>>(
&mut self,
var_name: &str,
attr_name: &str,
var_attr_value: T,
) -> Result<(), InvalidDataSet> {
self.add_var_attr_u8(
var_name,
attr_name,
String::from(var_attr_value.as_ref()).into_bytes(),
)
}
pub fn add_var_attr_i16(
&mut self,
var_name: &str,
attr_name: &str,
var_attr_value: Vec<i16>,
) -> Result<(), InvalidDataSet> {
let var_index: usize = self.find_var_from_name(var_name)?.0;
let var: &mut Variable = &mut self.vars[var_index];
var.add_attr_i16(attr_name, var_attr_value)?;
Ok(())
}
pub fn add_var_attr_i32(
&mut self,
var_name: &str,
attr_name: &str,
var_attr_value: Vec<i32>,
) -> Result<(), InvalidDataSet> {
let var_index: usize = self.find_var_from_name(var_name)?.0;
let var: &mut Variable = &mut self.vars[var_index];
var.add_attr_i32(attr_name, var_attr_value)?;
Ok(())
}
pub fn add_var_attr_f32(
&mut self,
var_name: &str,
attr_name: &str,
var_attr_value: Vec<f32>,
) -> Result<(), InvalidDataSet> {
let var_index: usize = self.find_var_from_name(var_name)?.0;
let var: &mut Variable = &mut self.vars[var_index];
var.add_attr_f32(attr_name, var_attr_value)?;
Ok(())
}
pub fn add_var_attr_f64(
&mut self,
var_name: &str,
attr_name: &str,
var_attr_value: Vec<f64>,
) -> Result<(), InvalidDataSet> {
let var_index: usize = self.find_var_from_name(var_name)?.0;
let var: &mut Variable = &mut self.vars[var_index];
var.add_attr_f64(attr_name, var_attr_value)?;
Ok(())
}
pub fn get_var_attr(&self, var_name: &str, attr_name: &str) -> Option<&Attribute> {
self.find_var_attr_from_name(var_name, attr_name)
.map(
|((_var_index, _var), (_attr_index, attr)): (
(usize, &Variable),
(usize, &Attribute),
)| { attr },
)
.ok()
}
pub fn get_var_attr_len(&self, var_name: &str, attr_name: &str) -> Option<usize> {
self.find_var_attr_from_name(var_name, attr_name)
.map(
|((_var_index, _var), (_attr_index, attr)): (
(usize, &Variable),
(usize, &Attribute),
)| { attr.len() },
)
.ok()
}
pub fn get_var_attr_data_type(&self, var_name: &str, attr_name: &str) -> Option<DataType> {
self.find_var_attr_from_name(var_name, attr_name)
.map(
|((_var_index, _var), (_attr_index, attr)): (
(usize, &Variable),
(usize, &Attribute),
)| { attr.data_type() },
)
.ok()
}
pub fn get_var_attrs(&self, var_name: &str) -> Option<Vec<&Attribute>> {
self.find_var_from_name(var_name)
.map(|(_var_index, ref_var): (usize, &Variable)| ref_var)
.ok()
.map(|ref_var: &Variable| ref_var.get_attrs())
}
pub fn has_var_attr(&self, var_name: &str, attr_name: &str) -> Option<bool> {
self.find_var_from_name(var_name)
.map(|(_var_index, var): (usize, &Variable)| var.has_attr(attr_name))
.ok()
}
pub fn num_var_attrs(&self, var_name: &str) -> Option<usize> {
self.find_var_from_name(var_name)
.map(|(_var_index, var): (usize, &Variable)| var.num_attrs())
.ok()
}
pub fn rename_var_attr(
&mut self,
var_name: &str,
old_attr_name: &str,
new_attr_name: &str,
) -> Result<(), InvalidDataSet> {
let var_index = self.find_var_from_name(var_name)?.0;
let var: &mut Variable = &mut self.vars[var_index];
var.rename_attr(old_attr_name, new_attr_name)?;
Ok(())
}
pub fn remove_var_attr(
&mut self,
var_name: &str,
attr_name: &str,
) -> Result<Attribute, InvalidDataSet> {
let var_index = self.find_var_from_name(var_name)?.0;
let var: &mut Variable = &mut self.vars[var_index];
var.remove_attr(attr_name)
}
#[allow(clippy::type_complexity)]
fn find_var_attr_from_name(
&self,
var_name: &str,
attr_name: &str,
) -> Result<((usize, &Variable), (usize, &Attribute)), InvalidDataSet> {
let (var_index, ref_var): (usize, &Variable) = self.find_var_from_name(var_name)?;
let (var_attr_index, ref_var_attr): (usize, &Attribute) =
ref_var.find_attr_from_name(attr_name)?;
Ok(((var_index, ref_var), (var_attr_index, ref_var_attr)))
}
pub fn get_var_attr_i8(&self, var_name: &str, attr_name: &str) -> Option<&[i8]> {
let attr: &Attribute = (self.find_var_attr_from_name(var_name, attr_name).ok()?.1).1;
attr.get_i8()
}
pub fn get_var_attr_u8(&self, var_name: &str, attr_name: &str) -> Option<&[u8]> {
let attr: &Attribute = (self.find_var_attr_from_name(var_name, attr_name).ok()?.1).1;
attr.get_u8()
}
pub fn get_var_attr_as_string(&self, var_name: &str, attr_name: &str) -> Option<String> {
let attr: &Attribute = (self.find_var_attr_from_name(var_name, attr_name).ok()?.1).1;
attr.get_as_string()
}
pub fn get_var_attr_i16(&self, var_name: &str, attr_name: &str) -> Option<&[i16]> {
let attr: &Attribute = (self.find_var_attr_from_name(var_name, attr_name).ok()?.1).1;
attr.get_i16()
}
pub fn get_var_attr_i32(&self, var_name: &str, attr_name: &str) -> Option<&[i32]> {
let attr: &Attribute = (self.find_var_attr_from_name(var_name, attr_name).ok()?.1).1;
attr.get_i32()
}
pub fn get_var_attr_f32(&self, var_name: &str, attr_name: &str) -> Option<&[f32]> {
let attr: &Attribute = (self.find_var_attr_from_name(var_name, attr_name).ok()?.1).1;
attr.get_f32()
}
pub fn get_var_attr_f64(&self, var_name: &str, attr_name: &str) -> Option<&[f64]> {
let attr: &Attribute = (self.find_var_attr_from_name(var_name, attr_name).ok()?.1).1;
attr.get_f64()
}
fn find_global_attr_from_name(
&self,
attr_name: &str,
) -> Result<(usize, &Attribute), InvalidDataSet> {
self.attrs
.iter()
.position(|ref_attr: &Attribute| ref_attr.name == attr_name)
.map(|attr_index: usize| (attr_index, &self.attrs[attr_index]))
.ok_or(InvalidDataSet::GlobalAttributeNotDefined(
attr_name.to_string(),
))
}
pub fn get_global_attr(&self, attr_name: &str) -> Option<&Attribute> {
self.find_global_attr_from_name(attr_name)
.ok()
.map(|(_attr_index, ref_attr)| ref_attr)
}
pub fn get_global_attrs(&self) -> Vec<&Attribute> {
self.attrs.iter().collect()
}
pub fn get_global_attr_len(&self, attr_name: &str) -> Option<usize> {
self.find_global_attr_from_name(attr_name)
.map(|(_attr_index, attr): (usize, &Attribute)| attr.len())
.ok()
}
pub fn get_global_attr_data_type(&self, attr_name: &str) -> Option<DataType> {
self.find_global_attr_from_name(attr_name)
.map(|(_attr_index, attr): (usize, &Attribute)| attr.data_type())
.ok()
}
pub fn num_global_attrs(&self) -> usize {
self.attrs.len()
}
pub fn has_global_attr(&self, attr_name: &str) -> bool {
self.find_global_attr_from_name(attr_name).is_ok()
}
pub fn get_global_attr_names(&self) -> Vec<String> {
self.attrs
.iter()
.map(|attr: &Attribute| attr.name().to_string())
.collect()
}
pub fn add_global_attr_i8(
&mut self,
attr_name: &str,
attr_data: Vec<i8>,
) -> Result<(), InvalidDataSet> {
if self.find_global_attr_from_name(attr_name).is_ok() {
return Err(InvalidDataSet::GlobalAttributeAlreadyExists(
attr_name.to_string(),
));
}
Attribute::check_attr_name(attr_name).map_err(|invalid_attr_name: String| {
InvalidDataSet::GlobalAttributeNameNotValid(invalid_attr_name)
})?;
self.attrs.push(Attribute {
name: attr_name.to_string(),
data: DataVector::I8(attr_data),
});
Ok(())
}
pub fn add_global_attr_u8(
&mut self,
attr_name: &str,
attr_data: Vec<u8>,
) -> Result<(), InvalidDataSet> {
if self.find_global_attr_from_name(attr_name).is_ok() {
return Err(InvalidDataSet::GlobalAttributeAlreadyExists(
attr_name.to_string(),
));
}
Attribute::check_attr_name(attr_name).map_err(|invalid_attr_name: String| {
InvalidDataSet::GlobalAttributeNameNotValid(invalid_attr_name)
})?;
self.attrs.push(Attribute {
name: attr_name.to_string(),
data: DataVector::U8(attr_data),
});
Ok(())
}
pub fn add_global_attr_string<T: AsRef<str>>(
&mut self,
attr_name: &str,
attr_data: T,
) -> Result<(), InvalidDataSet> {
self.add_global_attr_u8(attr_name, String::from(attr_data.as_ref()).into_bytes())
}
pub fn add_global_attr_i16(
&mut self,
attr_name: &str,
attr_data: Vec<i16>,
) -> Result<(), InvalidDataSet> {
if self.find_global_attr_from_name(attr_name).is_ok() {
return Err(InvalidDataSet::GlobalAttributeAlreadyExists(
attr_name.to_string(),
));
}
Attribute::check_attr_name(attr_name).map_err(|invalid_attr_name: String| {
InvalidDataSet::GlobalAttributeNameNotValid(invalid_attr_name)
})?;
self.attrs.push(Attribute {
name: attr_name.to_string(),
data: DataVector::I16(attr_data),
});
Ok(())
}
pub fn add_global_attr_i32(
&mut self,
attr_name: &str,
attr_data: Vec<i32>,
) -> Result<(), InvalidDataSet> {
if self.find_global_attr_from_name(attr_name).is_ok() {
return Err(InvalidDataSet::GlobalAttributeAlreadyExists(
attr_name.to_string(),
));
}
Attribute::check_attr_name(attr_name).map_err(|invalid_attr_name: String| {
InvalidDataSet::GlobalAttributeNameNotValid(invalid_attr_name)
})?;
self.attrs.push(Attribute {
name: attr_name.to_string(),
data: DataVector::I32(attr_data),
});
Ok(())
}
pub fn add_global_attr_f32(
&mut self,
attr_name: &str,
attr_data: Vec<f32>,
) -> Result<(), InvalidDataSet> {
if self.find_global_attr_from_name(attr_name).is_ok() {
return Err(InvalidDataSet::GlobalAttributeAlreadyExists(
attr_name.to_string(),
));
}
Attribute::check_attr_name(attr_name).map_err(|invalid_attr_name: String| {
InvalidDataSet::GlobalAttributeNameNotValid(invalid_attr_name)
})?;
self.attrs.push(Attribute {
name: attr_name.to_string(),
data: DataVector::F32(attr_data),
});
Ok(())
}
pub fn add_global_attr_f64(
&mut self,
attr_name: &str,
attr_data: Vec<f64>,
) -> Result<(), InvalidDataSet> {
if self.find_global_attr_from_name(attr_name).is_ok() {
return Err(InvalidDataSet::GlobalAttributeAlreadyExists(
attr_name.to_string(),
));
}
Attribute::check_attr_name(attr_name).map_err(|invalid_attr_name: String| {
InvalidDataSet::GlobalAttributeNameNotValid(invalid_attr_name)
})?;
self.attrs.push(Attribute {
name: attr_name.to_string(),
data: DataVector::F64(attr_data),
});
Ok(())
}
pub fn rename_global_attr(
&mut self,
old_attr_name: &str,
new_attr_name: &str,
) -> Result<(), InvalidDataSet> {
if old_attr_name == new_attr_name {
}
let renamed_attr_index = self.find_global_attr_from_name(old_attr_name)?.0;
if self.find_global_attr_from_name(new_attr_name).is_ok() {
return Err(InvalidDataSet::GlobalAttributeAlreadyExists(
new_attr_name.to_string(),
));
}
Attribute::check_attr_name(new_attr_name).map_err(|invalid_attr_name: String| {
InvalidDataSet::GlobalAttributeNameNotValid(invalid_attr_name)
})?;
self.attrs[renamed_attr_index].name = new_attr_name.to_string();
Ok(())
}
pub fn remove_global_attr(&mut self, attr_name: &str) -> Result<Attribute, InvalidDataSet> {
let removed_attr_index = self.find_global_attr_from_name(attr_name)?.0;
Ok(self.attrs.remove(removed_attr_index))
}
pub fn get_global_attr_i8(&self, attr_name: &str) -> Option<&[i8]> {
let attr: &Attribute = self.find_global_attr_from_name(attr_name).ok()?.1;
attr.get_i8()
}
pub fn get_global_attr_u8(&self, attr_name: &str) -> Option<&[u8]> {
let attr: &Attribute = self.find_global_attr_from_name(attr_name).ok()?.1;
attr.get_u8()
}
pub fn get_global_attr_as_string(&self, attr_name: &str) -> Option<String> {
let attr: &Attribute = self.find_global_attr_from_name(attr_name).ok()?.1;
attr.get_as_string()
}
pub fn get_global_attr_i16(&self, attr_name: &str) -> Option<&[i16]> {
let attr: &Attribute = self.find_global_attr_from_name(attr_name).ok()?.1;
attr.get_i16()
}
pub fn get_global_attr_i32(&self, attr_name: &str) -> Option<&[i32]> {
let attr: &Attribute = self.find_global_attr_from_name(attr_name).ok()?.1;
attr.get_i32()
}
pub fn get_global_attr_f32(&self, attr_name: &str) -> Option<&[f32]> {
let attr: &Attribute = self.find_global_attr_from_name(attr_name).ok()?.1;
attr.get_f32()
}
pub fn get_global_attr_f64(&self, attr_name: &str) -> Option<&[f64]> {
let attr: &Attribute = self.find_global_attr_from_name(attr_name).ok()?.1;
attr.get_f64()
}
pub fn record_size(&self) -> Option<usize> {
if !self.has_unlimited_dim() {
None
} else {
let (record_vars, _fixed_size_vars): (Vec<&Variable>, Vec<&Variable>) = self
.vars
.iter()
.partition(|var: &&Variable| var.is_record_var());
let record_size: usize = record_vars
.into_iter()
.fold(0, |sum: usize, var: &Variable| sum + var.chunk_size());
Some(record_size)
}
}
pub fn num_records(&self) -> Option<usize> {
self.unlimited_dim.as_ref().map(|dim| dim.size())
}
}