netcdf3/data_set/
dimension.rs

1mod tests;
2
3use crate::InvalidDataSet;
4use crate::NC_MAX_DIM_SIZE;
5use crate::name_string::is_valid_name;
6
7use std::cell::RefCell;
8
9/// NetCDF-3 dimension
10///
11/// `Dimension` instances are managed by the struct [`DataSet`](struct.DataSet.html).
12///
13/// `DataSet`s allow to create, get, remove and rename `Dimension`s.
14///
15/// # Examples
16///
17/// ## Create and get *fixed-size* and *unlimited-size* dimensions
18///
19/// ```
20/// use std::rc::Rc;
21/// use netcdf3::{DataSet, Dimension, DimensionType};
22///
23/// const DIM_NAME_1: &str = "dim_1";
24/// const DIM_SIZE_1: usize = 10;
25/// const DIM_NAME_2: &str = "dim_2";
26/// const DIM_SIZE_2: usize = 20;
27///
28/// // First create a data set
29/// let mut data_set = DataSet::new();
30///
31/// // Add one *fixed-size* dimensions and set the *unlimited-size* dimension
32/// data_set.set_unlimited_dim(DIM_NAME_1, DIM_SIZE_1).unwrap();
33/// data_set.add_fixed_dim(DIM_NAME_2, DIM_SIZE_2).unwrap();
34///
35/// // Read values throught the data set
36/// assert_eq!(2,                                   data_set.num_dims());
37/// assert_eq!(true,                                data_set.has_unlimited_dim());
38/// assert_eq!(true,                                data_set.has_dim(DIM_NAME_1));
39/// assert_eq!(Some(DIM_SIZE_1),                    data_set.dim_size(DIM_NAME_1));
40/// assert_eq!(Some(DimensionType::UnlimitedSize),  data_set.dim_type(DIM_NAME_1));
41/// assert_eq!(true,                                data_set.has_dim(DIM_NAME_2));
42/// assert_eq!(Some(DIM_SIZE_2),                    data_set.dim_size(DIM_NAME_2));
43/// assert_eq!(Some(DimensionType::FixedSize),      data_set.dim_type(DIM_NAME_2));
44///
45/// // Or through references of the dimensions
46/// let dim_1: Rc<Dimension> = data_set.get_dim(DIM_NAME_1).unwrap();
47/// assert_eq!(DIM_NAME_1,                          dim_1.name());
48/// assert_eq!(DIM_SIZE_1,                          dim_1.size());
49/// assert_eq!(true,                                dim_1.is_unlimited());
50/// assert_eq!(false,                               dim_1.is_fixed());
51/// assert_eq!(DimensionType::UnlimitedSize,        dim_1.dim_type());
52///
53/// let dim_2: Rc<Dimension> = data_set.get_dim(DIM_NAME_2).unwrap();
54/// assert_eq!(DIM_NAME_2,                          dim_2.name());
55/// assert_eq!(DIM_SIZE_2,                          dim_2.size());
56/// assert_eq!(false,                               dim_2.is_unlimited());
57/// assert_eq!(true,                                dim_2.is_fixed());
58/// assert_eq!(DimensionType::FixedSize,            dim_2.dim_type());
59///
60/// ```
61///
62/// ## Rename a dimension
63///
64/// ```
65/// use netcdf3::{DataSet, DimensionType};
66///
67/// const DIM_NAME_1: &str = "dim_1";
68/// const DIM_NAME_2: &str = "dim_2";
69/// const DIM_SIZE: usize = 10;
70///
71/// // First create a data set
72/// let mut data_set = DataSet::new();
73///
74/// // Add a *fixed-size* dimension
75/// data_set.add_fixed_dim(DIM_NAME_1, DIM_SIZE).unwrap();
76///
77/// assert_eq!(1,                                   data_set.num_dims());
78/// assert_eq!(false,                               data_set.has_unlimited_dim());
79/// assert_eq!(true,                                data_set.has_dim(DIM_NAME_1));
80/// assert_eq!(Some(DIM_SIZE),                      data_set.dim_size(DIM_NAME_1));
81/// assert_eq!(Some(DimensionType::FixedSize),      data_set.dim_type(DIM_NAME_1));
82/// assert_eq!(false,                               data_set.has_dim(DIM_NAME_2));
83/// assert_eq!(None,                                data_set.dim_size(DIM_NAME_2));
84/// assert_eq!(None,                                data_set.dim_type(DIM_NAME_2));
85///
86/// // Rename the *fixed-size* dimension
87/// data_set.rename_dim(DIM_NAME_1, DIM_NAME_2).unwrap();
88///
89/// assert_eq!(1,                                   data_set.num_dims());
90/// assert_eq!(false,                               data_set.has_unlimited_dim());
91/// assert_eq!(false,                               data_set.has_dim(DIM_NAME_1));
92/// assert_eq!(None,                                data_set.dim_size(DIM_NAME_1));
93/// assert_eq!(None,                                data_set.dim_type(DIM_NAME_1));
94/// assert_eq!(true,                                data_set.has_dim(DIM_NAME_2));
95/// assert_eq!(Some(DIM_SIZE),                      data_set.dim_size(DIM_NAME_2));
96/// assert_eq!(Some(DimensionType::FixedSize),      data_set.dim_type(DIM_NAME_2));
97/// ```
98///
99/// ## Remove a dimension
100///
101/// ```
102/// use std::rc::Rc;
103/// use netcdf3::{DataSet, Dimension, DimensionType};
104///
105/// const DIM_NAME: &str = "dim_1";
106/// const DIM_SIZE: usize = 10;
107///
108/// // First create a data set
109/// let mut data_set = DataSet::new();
110///
111/// // Set the *unlimited-size* dimension
112/// data_set.set_unlimited_dim(DIM_NAME, DIM_SIZE).unwrap();
113///
114/// assert_eq!(1,                                   data_set.num_dims());
115/// assert_eq!(true,                                data_set.has_unlimited_dim());
116/// assert_eq!(true,                                data_set.has_dim(DIM_NAME));
117/// assert_eq!(Some(DIM_SIZE),                      data_set.dim_size(DIM_NAME));
118/// assert_eq!(Some(DimensionType::UnlimitedSize),  data_set.dim_type(DIM_NAME));
119///
120/// // Remove the *unlimited-size* dimension
121/// let _removed_dim: Rc<Dimension> = data_set.remove_dim(DIM_NAME).unwrap();
122///
123/// assert_eq!(0,                                   data_set.num_dims());
124/// assert_eq!(false,                               data_set.has_unlimited_dim());
125/// assert_eq!(false,                               data_set.has_dim(DIM_NAME));
126/// assert_eq!(None,                                data_set.dim_size(DIM_NAME));
127/// assert_eq!(None,                                data_set.dim_type(DIM_NAME));
128/// ```
129#[derive(Debug, Clone, PartialEq, Eq)]
130pub struct Dimension {
131    pub(crate) name: RefCell<String>,
132    pub(crate) size: DimensionSize,
133}
134
135/// Internal representation of the size of a dimension.
136#[derive(Debug, Clone, PartialEq, Eq)]
137pub(crate) enum DimensionSize {
138    /// *Unlimited-size* dimension, the unlimited size can be modifed by the NetCDF-3 dataset.
139    Unlimited(RefCell<usize>),
140    /// *Fixed-size* dimension
141    Fixed(usize),
142}
143
144#[derive(Debug, Clone, PartialEq, Eq)]
145#[repr(u8)]
146/// Type of a dimension, *fixed* or *unlimited* size
147pub enum DimensionType {
148    UnlimitedSize = 0,
149    FixedSize = 1,
150}
151
152impl DimensionSize {
153    /// Create a new *unlimited* or *fixed* size.
154    pub(in crate::data_set) fn new(size: usize, r#type: DimensionType) -> DimensionSize {
155        return match r#type {
156            DimensionType::FixedSize => DimensionSize::Fixed(size),
157            DimensionType::UnlimitedSize => DimensionSize::Unlimited(RefCell::new(size)),
158        };
159    }
160
161    #[inline]
162    /// Return the size of the dimension.
163    pub(in crate::data_set) fn size(&self) -> usize {
164        return match self {
165            DimensionSize::Unlimited(size) => size.borrow().clone(),
166            DimensionSize::Fixed(size) => size.clone(),
167        };
168    }
169
170    #[inline]
171    /// Return the size of the dimension.
172    pub(in crate::data_set) fn r#type(&self) -> DimensionType {
173        return match self {
174            DimensionSize::Unlimited(_) => DimensionType::UnlimitedSize,
175            DimensionSize::Fixed(_) => DimensionType::FixedSize,
176        };
177    }
178}
179
180impl Dimension {
181
182    /// Creates a new *fixed size* NetCDF-3 dimension.
183    pub(crate) fn new_fixed_size(name: &str, size: usize) -> Result<Dimension, InvalidDataSet> {
184        Dimension::check_dim_name(name)?;
185        if size == 0 {
186            return Err(InvalidDataSet::FixedDimensionWithZeroSize(name.to_string()));
187        }
188        if size > NC_MAX_DIM_SIZE {
189            return Err(InvalidDataSet::MaximumFixedDimensionSizeExceeded{dim_name: name.to_string(), get: size});
190        }
191        return Ok(Dimension {
192            name: RefCell::new(name.to_string()),
193            size: DimensionSize::new(size, DimensionType::FixedSize),
194        });
195    }
196
197    /// Creates a new *unlimited size* NetCDF-3 dimension.
198    pub(crate) fn new_unlimited_size(name: &str, size: usize) -> Result<Dimension, InvalidDataSet> {
199        Dimension::check_dim_name(name)?;
200        return Ok(Dimension {
201            name: RefCell::new(name.to_string()),
202            size: DimensionSize::new(size, DimensionType::UnlimitedSize),
203        });
204    }
205
206    /// Returns the name of the NetCDF-3 dimension.
207    pub fn name(&self) -> String {
208        return self.name.borrow().clone();
209    }
210
211    /// Returns the size of the NetCDF-3 dimension.
212    pub fn size(&self) -> usize {
213        return self.size.size();
214    }
215
216    /// Returns the dimension type (*fixed size* ou *unlimited size*) of the NetCDF-3 dimension.
217    pub fn dim_type(&self) -> DimensionType {
218        return self.size.r#type();
219    }
220
221    /// Returns `true` if the dimension is a *unlimited size* dimension, otherwise return `false`.
222    pub fn is_unlimited(&self) -> bool {
223        return self.dim_type() == DimensionType::UnlimitedSize;
224    }
225
226    /// Returns `true` if the dimension is a *fixed size* dimension, otherwise return `false`.
227    pub fn is_fixed(&self) -> bool {
228        return self.dim_type() == DimensionType::FixedSize;
229    }
230
231    pub(in crate::data_set) fn check_dim_name(dim_name: &str) -> Result<(), InvalidDataSet> {
232        return match is_valid_name(dim_name) {
233            true => Ok(()),
234            false => Err(InvalidDataSet::DimensionNameNotValid(dim_name.to_string())),
235        };
236    }
237}