use super::attribute::AttrValue;
use super::attribute::Attribute;
use super::dimension::Dimension;
use super::error;
use super::variable::{Numeric, Variable, VariableMut};
use netcdf_sys::*;
use std::convert::TryInto;
use std::marker::PhantomData;
#[derive(Debug, Clone)]
pub struct Group<'f> {
pub(crate) ncid: nc_type,
pub(crate) _file: PhantomData<&'f nc_type>,
}
#[derive(Debug)]
#[allow(clippy::module_name_repetitions)]
pub struct GroupMut<'f>(
pub(crate) Group<'f>,
pub(crate) PhantomData<&'f mut nc_type>,
);
impl<'f> std::ops::Deref for GroupMut<'f> {
type Target = Group<'f>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'f> Group<'f> {
pub fn name(&self) -> String {
let mut name = vec![0_u8; NC_MAX_NAME as usize + 1];
unsafe {
error::checked(super::with_lock(|| {
nc_inq_grpname(self.ncid, name.as_mut_ptr() as *mut _)
}))
.unwrap();
}
let zeropos = name
.iter()
.position(|&x| x == 0)
.unwrap_or_else(|| name.len());
name.resize(zeropos, 0);
String::from_utf8(name).expect("Group did not have a valid name")
}
fn id(&self) -> nc_type {
self.ncid
}
pub fn variable<'g>(&'g self, name: &str) -> Option<Variable<'g>>
where
'f: 'g,
{
Variable::find_from_name(self.id(), name).unwrap()
}
pub fn variables<'g>(&'g self) -> impl Iterator<Item = Variable<'g>>
where
'f: 'g,
{
super::variable::variables_at_ncid(self.id())
.unwrap()
.map(Result::unwrap)
}
pub fn attribute<'a>(&'a self, name: &str) -> Option<Attribute<'a>> {
Attribute::find_from_name(self.ncid, None, name).unwrap()
}
pub fn attributes(&self) -> impl Iterator<Item = Attribute> {
crate::attribute::AttributeIterator::new(self.ncid, None)
.unwrap()
.map(Result::unwrap)
}
pub fn dimension<'g>(&'g self, name: &str) -> Option<Dimension<'g>>
where
'f: 'g,
{
super::dimension::dimension_from_name(self.id(), name).unwrap()
}
pub fn dimensions<'g>(&'g self) -> impl Iterator<Item = Dimension<'g>>
where
'f: 'g,
{
super::dimension::dimensions_from_location(self.id())
.unwrap()
.map(Result::unwrap)
}
pub fn group<'g>(&'g self, name: &str) -> Option<Group<'g>>
where
'f: 'g,
{
group_from_name(self.id(), name).unwrap()
}
pub fn groups<'g>(&'g self) -> impl Iterator<Item = Group<'g>>
where
'f: 'g,
{
groups_at_ncid(self.id()).unwrap()
}
pub fn types(&self) -> impl Iterator<Item = super::types::VariableType> {
super::types::all_at_location(self.ncid)
.map(|x| x.map(Result::unwrap))
.unwrap()
}
}
impl<'f> GroupMut<'f> {
pub fn variable_mut<'g>(&'g mut self, name: &str) -> Option<VariableMut<'g>>
where
'f: 'g,
{
self.variable(name).map(|v| VariableMut(v, PhantomData))
}
pub fn variables_mut<'g>(&'g mut self) -> impl Iterator<Item = VariableMut<'g>>
where
'f: 'g,
{
self.variables().map(|var| VariableMut(var, PhantomData))
}
pub fn group_mut<'g>(&'g mut self, name: &str) -> Option<GroupMut<'g>>
where
'f: 'g,
{
self.group(name).map(|g| GroupMut(g, PhantomData))
}
pub fn groups_mut<'g>(&'g mut self) -> impl Iterator<Item = GroupMut<'g>>
where
'f: 'g,
{
self.groups().map(|g| GroupMut(g, PhantomData))
}
pub fn add_opaque_type(
&'f mut self,
name: &str,
size: usize,
) -> error::Result<super::types::OpaqueType> {
super::types::OpaqueType::add(self.id(), name, size)
}
pub fn add_vlen_type<T: Numeric>(
&'f mut self,
name: &str,
) -> error::Result<super::types::VlenType> {
super::types::VlenType::add::<T>(self.id(), name)
}
pub fn add_enum_type<T: Numeric>(
&'f mut self,
name: &str,
mappings: &[(&str, T)],
) -> error::Result<super::types::EnumType> {
super::types::EnumType::add::<T>(self.id(), name, mappings)
}
pub fn add_compound_type(
&mut self,
name: &str,
) -> error::Result<super::types::CompoundBuilder> {
super::types::CompoundType::add(self.id(), name)
}
pub fn add_attribute<'a, T>(&'a mut self, name: &str, val: T) -> error::Result<Attribute<'a>>
where
T: Into<AttrValue>,
{
Attribute::put(self.ncid, NC_GLOBAL, name, val.into())
}
pub fn add_dimension<'g>(&'g mut self, name: &str, len: usize) -> error::Result<Dimension<'g>> {
super::dimension::add_dimension_at(self.id(), name, len)
}
pub fn add_unlimited_dimension<'g>(&'g mut self, name: &str) -> error::Result<Dimension<'g>> {
self.add_dimension(name, 0)
}
pub(crate) fn add_group_at(ncid: nc_type, name: &str) -> error::Result<Self> {
let byte_name = super::utils::short_name_to_bytes(name)?;
let mut grpid = 0;
unsafe {
error::checked(super::with_lock(|| {
nc_def_grp(ncid, byte_name.as_ptr() as *const _, &mut grpid)
}))?;
}
Ok(Self(
Group {
ncid: grpid,
_file: PhantomData,
},
PhantomData,
))
}
pub fn add_group<'g>(&'g mut self, name: &str) -> error::Result<GroupMut<'g>>
where
'f: 'g,
{
Self::add_group_at(self.id(), name)
}
pub fn add_variable<'g, T>(
&'g mut self,
name: &str,
dims: &[&str],
) -> error::Result<VariableMut<'g>>
where
T: Numeric,
'f: 'g,
{
VariableMut::add_from_str(self.id(), T::NCTYPE, name, dims)
}
pub fn add_string_variable<'g>(
&mut self,
name: &str,
dims: &[&str],
) -> error::Result<VariableMut<'g>> {
VariableMut::add_from_str(self.id(), NC_STRING, name, dims)
}
pub fn add_variable_from_identifiers<'g, T>(
&'g mut self,
name: &str,
dims: &[super::dimension::Identifier],
) -> error::Result<VariableMut<'g>>
where
T: Numeric,
{
super::variable::add_variable_from_identifiers(self.id(), name, dims, T::NCTYPE)
}
pub fn add_variable_with_type(
&'f mut self,
name: &str,
dims: &[&str],
typ: &super::types::VariableType,
) -> error::Result<VariableMut<'f>> {
VariableMut::add_from_str(self.id(), typ.id(), name, dims)
}
}
pub(crate) fn groups_at_ncid<'f>(ncid: nc_type) -> error::Result<impl Iterator<Item = Group<'f>>> {
let mut num_grps = 0;
unsafe {
error::checked(super::with_lock(|| {
nc_inq_grps(ncid, &mut num_grps, std::ptr::null_mut())
}))?;
}
let mut grps = vec![0; num_grps.try_into()?];
unsafe {
error::checked(super::with_lock(|| {
nc_inq_grps(ncid, std::ptr::null_mut(), grps.as_mut_ptr())
}))?;
}
Ok(grps.into_iter().map(|id| Group {
ncid: id,
_file: PhantomData,
}))
}
pub(crate) fn group_from_name<'f>(ncid: nc_type, name: &str) -> error::Result<Option<Group<'f>>> {
let byte_name = super::utils::short_name_to_bytes(name)?;
let mut grpid = 0;
let e = unsafe {
super::with_lock(|| nc_inq_grp_ncid(ncid, byte_name.as_ptr() as *const _, &mut grpid))
};
if e == NC_ENOGRP {
return Ok(None);
} else {
error::checked(e)?;
}
Ok(Some(Group {
ncid: grpid,
_file: PhantomData,
}))
}