1use serde::{Deserialize, Serialize};
7
8use crate::error::{NetCdfError, Result};
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub enum AttributeValue {
13 Text(String),
15 I8(Vec<i8>),
17 U8(Vec<u8>),
19 I16(Vec<i16>),
21 U16(Vec<u16>),
23 I32(Vec<i32>),
25 U32(Vec<u32>),
27 I64(Vec<i64>),
29 U64(Vec<u64>),
31 F32(Vec<f32>),
33 F64(Vec<f64>),
35}
36
37impl AttributeValue {
38 #[must_use]
40 pub fn text(s: impl Into<String>) -> Self {
41 Self::Text(s.into())
42 }
43
44 #[must_use]
46 pub fn i8(value: i8) -> Self {
47 Self::I8(vec![value])
48 }
49
50 #[must_use]
52 pub fn i8_array(values: Vec<i8>) -> Self {
53 Self::I8(values)
54 }
55
56 #[must_use]
58 pub fn u8(value: u8) -> Self {
59 Self::U8(vec![value])
60 }
61
62 #[must_use]
64 pub fn u8_array(values: Vec<u8>) -> Self {
65 Self::U8(values)
66 }
67
68 #[must_use]
70 pub fn i16(value: i16) -> Self {
71 Self::I16(vec![value])
72 }
73
74 #[must_use]
76 pub fn i16_array(values: Vec<i16>) -> Self {
77 Self::I16(values)
78 }
79
80 #[must_use]
82 pub fn u16(value: u16) -> Self {
83 Self::U16(vec![value])
84 }
85
86 #[must_use]
88 pub fn u16_array(values: Vec<u16>) -> Self {
89 Self::U16(values)
90 }
91
92 #[must_use]
94 pub fn i32(value: i32) -> Self {
95 Self::I32(vec![value])
96 }
97
98 #[must_use]
100 pub fn i32_array(values: Vec<i32>) -> Self {
101 Self::I32(values)
102 }
103
104 #[must_use]
106 pub fn u32(value: u32) -> Self {
107 Self::U32(vec![value])
108 }
109
110 #[must_use]
112 pub fn u32_array(values: Vec<u32>) -> Self {
113 Self::U32(values)
114 }
115
116 #[must_use]
118 pub fn i64(value: i64) -> Self {
119 Self::I64(vec![value])
120 }
121
122 #[must_use]
124 pub fn i64_array(values: Vec<i64>) -> Self {
125 Self::I64(values)
126 }
127
128 #[must_use]
130 pub fn u64(value: u64) -> Self {
131 Self::U64(vec![value])
132 }
133
134 #[must_use]
136 pub fn u64_array(values: Vec<u64>) -> Self {
137 Self::U64(values)
138 }
139
140 #[must_use]
142 pub fn f32(value: f32) -> Self {
143 Self::F32(vec![value])
144 }
145
146 #[must_use]
148 pub fn f32_array(values: Vec<f32>) -> Self {
149 Self::F32(values)
150 }
151
152 #[must_use]
154 pub fn f64(value: f64) -> Self {
155 Self::F64(vec![value])
156 }
157
158 #[must_use]
160 pub fn f64_array(values: Vec<f64>) -> Self {
161 Self::F64(values)
162 }
163
164 pub fn as_text(&self) -> Result<&str> {
170 match self {
171 Self::Text(s) => Ok(s),
172 _ => Err(NetCdfError::AttributeError(
173 "Attribute is not text".to_string(),
174 )),
175 }
176 }
177
178 pub fn as_i32(&self) -> Result<i32> {
184 match self {
185 Self::I32(values) if values.len() == 1 => Ok(values[0]),
186 Self::I32(_) => Err(NetCdfError::AttributeError(
187 "Attribute has multiple values".to_string(),
188 )),
189 _ => Err(NetCdfError::AttributeError(
190 "Attribute is not i32".to_string(),
191 )),
192 }
193 }
194
195 pub fn as_f32(&self) -> Result<f32> {
201 match self {
202 Self::F32(values) if values.len() == 1 => Ok(values[0]),
203 Self::F32(_) => Err(NetCdfError::AttributeError(
204 "Attribute has multiple values".to_string(),
205 )),
206 _ => Err(NetCdfError::AttributeError(
207 "Attribute is not f32".to_string(),
208 )),
209 }
210 }
211
212 pub fn as_f64(&self) -> Result<f64> {
218 match self {
219 Self::F64(values) if values.len() == 1 => Ok(values[0]),
220 Self::F64(_) => Err(NetCdfError::AttributeError(
221 "Attribute has multiple values".to_string(),
222 )),
223 _ => Err(NetCdfError::AttributeError(
224 "Attribute is not f64".to_string(),
225 )),
226 }
227 }
228
229 #[must_use]
231 pub const fn type_name(&self) -> &'static str {
232 match self {
233 Self::Text(_) => "text",
234 Self::I8(_) => "i8",
235 Self::U8(_) => "u8",
236 Self::I16(_) => "i16",
237 Self::U16(_) => "u16",
238 Self::I32(_) => "i32",
239 Self::U32(_) => "u32",
240 Self::I64(_) => "i64",
241 Self::U64(_) => "u64",
242 Self::F32(_) => "f32",
243 Self::F64(_) => "f64",
244 }
245 }
246
247 #[must_use]
249 pub fn len(&self) -> usize {
250 match self {
251 Self::Text(s) => s.len(),
252 Self::I8(v) => v.len(),
253 Self::U8(v) => v.len(),
254 Self::I16(v) => v.len(),
255 Self::U16(v) => v.len(),
256 Self::I32(v) => v.len(),
257 Self::U32(v) => v.len(),
258 Self::I64(v) => v.len(),
259 Self::U64(v) => v.len(),
260 Self::F32(v) => v.len(),
261 Self::F64(v) => v.len(),
262 }
263 }
264
265 #[must_use]
267 pub fn is_empty(&self) -> bool {
268 self.len() == 0
269 }
270}
271
272#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
274pub struct Attribute {
275 name: String,
277 value: AttributeValue,
279}
280
281impl Attribute {
282 pub fn new(name: impl Into<String>, value: AttributeValue) -> Result<Self> {
293 let name = name.into();
294 if name.is_empty() {
295 return Err(NetCdfError::AttributeError(
296 "Attribute name cannot be empty".to_string(),
297 ));
298 }
299 Ok(Self { name, value })
300 }
301
302 #[must_use]
304 pub fn name(&self) -> &str {
305 &self.name
306 }
307
308 #[must_use]
310 pub const fn value(&self) -> &AttributeValue {
311 &self.value
312 }
313
314 pub fn value_mut(&mut self) -> &mut AttributeValue {
316 &mut self.value
317 }
318}
319
320#[derive(Debug, Clone, Default, Serialize, Deserialize)]
322pub struct Attributes {
323 attributes: Vec<Attribute>,
324}
325
326impl Attributes {
327 #[must_use]
329 pub const fn new() -> Self {
330 Self {
331 attributes: Vec::new(),
332 }
333 }
334
335 #[must_use]
337 pub const fn from_vec(attributes: Vec<Attribute>) -> Self {
338 Self { attributes }
339 }
340
341 pub fn add(&mut self, attribute: Attribute) -> Result<()> {
347 if self.contains(attribute.name()) {
348 return Err(NetCdfError::AttributeError(format!(
349 "Attribute '{}' already exists",
350 attribute.name()
351 )));
352 }
353 self.attributes.push(attribute);
354 Ok(())
355 }
356
357 pub fn set(&mut self, attribute: Attribute) {
359 if let Some(existing) = self.get_mut(attribute.name()) {
360 *existing = attribute;
361 } else {
362 self.attributes.push(attribute);
363 }
364 }
365
366 #[must_use]
368 pub fn get(&self, name: &str) -> Option<&Attribute> {
369 self.attributes.iter().find(|a| a.name() == name)
370 }
371
372 pub fn get_mut(&mut self, name: &str) -> Option<&mut Attribute> {
374 self.attributes.iter_mut().find(|a| a.name() == name)
375 }
376
377 #[must_use]
379 pub fn get_value(&self, name: &str) -> Option<&AttributeValue> {
380 self.get(name).map(|a| a.value())
381 }
382
383 #[must_use]
385 pub fn contains(&self, name: &str) -> bool {
386 self.attributes.iter().any(|a| a.name() == name)
387 }
388
389 #[must_use]
391 pub fn len(&self) -> usize {
392 self.attributes.len()
393 }
394
395 #[must_use]
397 pub fn is_empty(&self) -> bool {
398 self.attributes.is_empty()
399 }
400
401 pub fn iter(&self) -> impl Iterator<Item = &Attribute> {
403 self.attributes.iter()
404 }
405
406 #[must_use]
408 pub fn names(&self) -> Vec<&str> {
409 self.attributes.iter().map(|a| a.name()).collect()
410 }
411
412 pub fn remove(&mut self, name: &str) -> Option<Attribute> {
414 self.attributes
415 .iter()
416 .position(|a| a.name() == name)
417 .map(|index| self.attributes.remove(index))
418 }
419}
420
421impl IntoIterator for Attributes {
422 type Item = Attribute;
423 type IntoIter = std::vec::IntoIter<Attribute>;
424
425 fn into_iter(self) -> Self::IntoIter {
426 self.attributes.into_iter()
427 }
428}
429
430impl<'a> IntoIterator for &'a Attributes {
431 type Item = &'a Attribute;
432 type IntoIter = std::slice::Iter<'a, Attribute>;
433
434 fn into_iter(self) -> Self::IntoIter {
435 self.attributes.iter()
436 }
437}
438
439impl FromIterator<Attribute> for Attributes {
440 fn from_iter<T: IntoIterator<Item = Attribute>>(iter: T) -> Self {
441 Self {
442 attributes: iter.into_iter().collect(),
443 }
444 }
445}
446
447#[cfg(test)]
448mod tests {
449 #![allow(clippy::panic)]
451 #![allow(clippy::expect_used)]
452
453 use super::*;
454
455 #[test]
456 fn test_text_attribute() {
457 let attr = Attribute::new("title", AttributeValue::text("Test Data"))
458 .expect("Failed to create text attribute");
459 assert_eq!(attr.name(), "title");
460 assert_eq!(
461 attr.value().as_text().expect("Failed to get text value"),
462 "Test Data"
463 );
464 }
465
466 #[test]
467 fn test_numeric_attribute() {
468 let attr = Attribute::new("scale_factor", AttributeValue::f64(1.5))
469 .expect("Failed to create numeric attribute");
470 assert_eq!(attr.name(), "scale_factor");
471 assert_eq!(attr.value().as_f64().expect("Failed to get f64 value"), 1.5);
472 }
473
474 #[test]
475 fn test_array_attribute() {
476 let values = vec![1.0, 2.0, 3.0];
477 let attr = Attribute::new("coefficients", AttributeValue::f64_array(values.clone()))
478 .expect("Failed to create array attribute");
479 assert_eq!(attr.name(), "coefficients");
480 match attr.value() {
481 AttributeValue::F64(v) => assert_eq!(v, &values),
482 other => {
483 panic!("Expected F64 attribute value, got {:?}", other);
484 }
485 }
486 }
487
488 #[test]
489 fn test_attribute_collection() {
490 let mut attrs = Attributes::new();
491 attrs
492 .add(
493 Attribute::new("title", AttributeValue::text("Test"))
494 .expect("Failed to create title attribute"),
495 )
496 .expect("Failed to add title attribute");
497 attrs
498 .add(
499 Attribute::new("version", AttributeValue::i32(1))
500 .expect("Failed to create version attribute"),
501 )
502 .expect("Failed to add version attribute");
503
504 assert_eq!(attrs.len(), 2);
505 assert!(attrs.contains("title"));
506 assert!(attrs.contains("version"));
507
508 let title = attrs.get("title").expect("Failed to get title attribute");
509 assert_eq!(
510 title.value().as_text().expect("Failed to get text value"),
511 "Test"
512 );
513 }
514
515 #[test]
516 fn test_empty_attribute_name() {
517 let result = Attribute::new("", AttributeValue::text("test"));
518 assert!(result.is_err());
519 }
520
521 #[test]
522 fn test_duplicate_attribute() {
523 let mut attrs = Attributes::new();
524 attrs
525 .add(
526 Attribute::new("test", AttributeValue::i32(1))
527 .expect("Failed to create first test attribute"),
528 )
529 .expect("Failed to add first test attribute");
530 let result = attrs.add(
531 Attribute::new("test", AttributeValue::i32(2))
532 .expect("Failed to create second test attribute"),
533 );
534 assert!(result.is_err());
535 }
536
537 #[test]
538 fn test_attribute_set() {
539 let mut attrs = Attributes::new();
540 attrs.set(
541 Attribute::new("test", AttributeValue::i32(1))
542 .expect("Failed to create test attribute with value 1"),
543 );
544 assert_eq!(
545 attrs
546 .get("test")
547 .expect("Failed to get test attribute")
548 .value()
549 .as_i32()
550 .expect("Failed to get i32 value"),
551 1
552 );
553
554 attrs.set(
556 Attribute::new("test", AttributeValue::i32(2))
557 .expect("Failed to create test attribute with value 2"),
558 );
559 assert_eq!(
560 attrs
561 .get("test")
562 .expect("Failed to get test attribute after replacement")
563 .value()
564 .as_i32()
565 .expect("Failed to get i32 value after replacement"),
566 2
567 );
568 assert_eq!(attrs.len(), 1);
569 }
570
571 #[test]
572 fn test_attribute_remove() {
573 let mut attrs = Attributes::new();
574 attrs.set(
575 Attribute::new("test", AttributeValue::i32(1))
576 .expect("Failed to create test attribute for removal test"),
577 );
578 assert!(attrs.contains("test"));
579
580 let removed = attrs.remove("test");
581 assert!(removed.is_some());
582 assert!(!attrs.contains("test"));
583 }
584}