Skip to content

Commit

Permalink
Merge pull request #117 from magnusuMET/feature/AttrValue_tryfrom
Browse files Browse the repository at this point in the history
Add TryFrom for AttrValue
  • Loading branch information
magnusuMET authored Oct 8, 2023
2 parents d083075 + 857375d commit ba55f28
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 1 deletion.
180 changes: 179 additions & 1 deletion netcdf/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#![allow(clippy::similar_names)]
use super::error;
use netcdf_sys::*;
use std::convert::TryInto;
use std::ffi::{CStr, CString};
use std::marker::PhantomData;
use std::os::raw::c_char;
Expand Down Expand Up @@ -887,3 +886,182 @@ fn conversion() {
let x = 1.0f32;
let _b: AttrValue = x.into();
}

impl TryFrom<AttrValue> for u8 {
type Error = error::Error;
fn try_from(attr: AttrValue) -> Result<u8, Self::Error> {
match attr {
AttrValue::Uchar(x) => Ok(x),
AttrValue::Schar(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Ushort(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Short(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Uint(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Int(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Ulonglong(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Longlong(x) => (x).try_into().map_err(error::Error::Conversion),
_ => Err("Conversion not supported".into()),
}
}
}

impl TryFrom<AttrValue> for i8 {
type Error = error::Error;
fn try_from(attr: AttrValue) -> Result<i8, Self::Error> {
match attr {
AttrValue::Uchar(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Schar(x) => Ok(x),
AttrValue::Ushort(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Short(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Uint(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Int(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Ulonglong(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Longlong(x) => (x).try_into().map_err(error::Error::Conversion),
_ => Err("Conversion not supported".into()),
}
}
}

impl TryFrom<AttrValue> for u16 {
type Error = error::Error;
fn try_from(attr: AttrValue) -> Result<u16, Self::Error> {
match attr {
AttrValue::Uchar(x) => Ok((x).into()),
AttrValue::Schar(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Ushort(x) => Ok(x),
AttrValue::Short(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Uint(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Int(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Ulonglong(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Longlong(x) => (x).try_into().map_err(error::Error::Conversion),
_ => Err("Conversion not supported".into()),
}
}
}

impl TryFrom<AttrValue> for i16 {
type Error = error::Error;
fn try_from(attr: AttrValue) -> Result<i16, Self::Error> {
match attr {
AttrValue::Uchar(x) => Ok((x).into()),
AttrValue::Schar(x) => Ok((x).into()),
AttrValue::Ushort(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Short(x) => Ok(x),
AttrValue::Uint(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Int(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Ulonglong(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Longlong(x) => (x).try_into().map_err(error::Error::Conversion),
_ => Err("Conversion not supported".into()),
}
}
}
impl TryFrom<AttrValue> for u32 {
type Error = error::Error;
fn try_from(attr: AttrValue) -> Result<u32, Self::Error> {
match attr {
AttrValue::Uchar(x) => Ok((x).into()),
AttrValue::Schar(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Ushort(x) => Ok((x).into()),
AttrValue::Short(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Uint(x) => Ok(x),
AttrValue::Int(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Ulonglong(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Longlong(x) => (x).try_into().map_err(error::Error::Conversion),
_ => Err("Conversion not supported".into()),
}
}
}
impl TryFrom<AttrValue> for i32 {
type Error = error::Error;
fn try_from(attr: AttrValue) -> Result<i32, Self::Error> {
match attr {
AttrValue::Uchar(x) => Ok((x).into()),
AttrValue::Schar(x) => Ok((x).into()),
AttrValue::Ushort(x) => Ok((x).into()),
AttrValue::Short(x) => Ok((x).into()),
AttrValue::Uint(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Int(x) => Ok(x),
AttrValue::Ulonglong(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Longlong(x) => (x).try_into().map_err(error::Error::Conversion),
_ => Err("Conversion not supported".into()),
}
}
}
impl TryFrom<AttrValue> for u64 {
type Error = error::Error;
fn try_from(attr: AttrValue) -> Result<u64, Self::Error> {
match attr {
AttrValue::Uchar(x) => Ok((x).into()),
AttrValue::Schar(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Ushort(x) => Ok((x).into()),
AttrValue::Short(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Uint(x) => Ok((x).into()),
AttrValue::Int(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Ulonglong(x) => Ok(x),
AttrValue::Longlong(x) => (x).try_into().map_err(error::Error::Conversion),
_ => Err("Conversion not supported".into()),
}
}
}
impl TryFrom<AttrValue> for i64 {
type Error = error::Error;
fn try_from(attr: AttrValue) -> Result<i64, Self::Error> {
match attr {
AttrValue::Uchar(x) => Ok((x).into()),
AttrValue::Schar(x) => Ok((x).into()),
AttrValue::Ushort(x) => Ok((x).into()),
AttrValue::Short(x) => Ok((x).into()),
AttrValue::Uint(x) => Ok((x).into()),
AttrValue::Int(x) => Ok((x).into()),
AttrValue::Ulonglong(x) => (x).try_into().map_err(error::Error::Conversion),
AttrValue::Longlong(x) => Ok(x),
_ => Err("Conversion not supported".into()),
}
}
}
impl TryFrom<AttrValue> for f32 {
type Error = error::Error;
fn try_from(attr: AttrValue) -> Result<f32, Self::Error> {
match attr {
AttrValue::Uchar(x) => Ok(x as _),
AttrValue::Schar(x) => Ok(x as _),
AttrValue::Ushort(x) => Ok(x as _),
AttrValue::Short(x) => Ok(x as _),
AttrValue::Uint(x) => Ok(x as _),
AttrValue::Int(x) => Ok(x as _),
AttrValue::Ulonglong(x) => Ok(x as _),
AttrValue::Longlong(x) => Ok(x as _),
AttrValue::Float(x) => Ok(x),
AttrValue::Double(x) => Ok(x as _),
_ => Err("Conversion not supported".into()),
}
}
}
impl TryFrom<AttrValue> for f64 {
type Error = error::Error;
fn try_from(attr: AttrValue) -> Result<f64, Self::Error> {
match attr {
AttrValue::Uchar(x) => Ok(x as _),
AttrValue::Schar(x) => Ok(x as _),
AttrValue::Ushort(x) => Ok(x as _),
AttrValue::Short(x) => Ok(x as _),
AttrValue::Uint(x) => Ok(x as _),
AttrValue::Int(x) => Ok(x as _),
AttrValue::Ulonglong(x) => Ok(x as _),
AttrValue::Longlong(x) => Ok(x as _),
AttrValue::Float(x) => Ok(x as _),
AttrValue::Double(x) => Ok(x),
_ => Err("Conversion not supported".into()),
}
}
}

#[test]
fn roundtrip_attrvalue() {
let x: u8 = 5;
let attr: AttrValue = x.into();
assert_eq!(x, attr.try_into().unwrap());

let x: f32 = 5.0;
let attr: AttrValue = x.into();
assert_eq!(x, attr.try_into().unwrap());
}
4 changes: 4 additions & 0 deletions netcdf/src/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ impl<'f> Group<'f> {
.unwrap()
.map(Result::unwrap)
}
/// Get the attribute value
pub fn attribute_value(&self, name: &str) -> Option<error::Result<AttrValue>> {
self.attribute(name).as_ref().map(Attribute::value)
}

/// Get a single dimension
pub fn dimension<'g>(&'g self, name: &str) -> Option<Dimension<'g>>
Expand Down
21 changes: 21 additions & 0 deletions netcdf/src/variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ impl<'g> Variable<'g> {
.expect("Could not get attributes")
.map(Result::unwrap)
}
/// Get the attribute value
pub fn attribute_value(&self, name: &str) -> Option<error::Result<AttrValue>> {
self.attribute(name).as_ref().map(Attribute::value)
}
/// Dimensions for a variable
pub fn dimensions(&self) -> &[Dimension] {
&self.dimensions
Expand Down Expand Up @@ -784,6 +788,23 @@ impl<'g> Variable<'g> {
}

/// Get multiple values from a variable
///
/// Take notice:
/// `scale_factor` and `offset_factor` and other attributes are not
/// automatically applied. To take such into account, you can use code like below
/// ```rust,no_run
/// # use netcdf::attribute::AttrValue;
/// # let f = netcdf::create("file.nc")?;
/// # let var = f.variable("stuff").unwrap();
/// // let var = ...
/// // let values = ...
/// if let Some(scale_offset) = var.attribute_value("scale_offset").transpose()? {
/// let scale_offset: f64 = scale_offset.try_into()?;
/// // values += scale_offset
/// }
/// # Result::<(), netcdf::error::Error>::Ok(())
/// ```
/// where `Option::transpose` is used to bubble up any read errors
pub fn values<T: NcPutGet, E>(&self, extents: E) -> error::Result<Vec<T>>
where
E: TryInto<Extents>,
Expand Down

0 comments on commit ba55f28

Please sign in to comment.