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}