Skip to main content

fits_io/bin_table/
row.rs

1use crate::bin_table::FieldDefinition;
2#[cfg(feature = "serde")]
3use crate::bin_table::row_columns::RowColumns;
4use crate::bin_table::value::Value;
5
6/// A data row
7#[derive(Debug, Clone)]
8pub struct Row<'a> {
9    data: &'a [u8],
10    /// The table's heap, where variable length array columns keep their values.
11    /// Empty for a table that has none.
12    heap: &'a [u8],
13    field_definitions: &'a Vec<FieldDefinition>,
14}
15
16impl<'a> Row<'a> {
17    pub(crate) fn new(
18        field_definitions: &'a Vec<FieldDefinition>,
19        data: &'a [u8],
20        heap: &'a [u8],
21    ) -> Self {
22        Self {
23            data,
24            heap,
25            field_definitions,
26        }
27    }
28
29    /// The columns this row is made of.
30    pub fn field_definitions(&self) -> &'a [FieldDefinition] {
31        self.field_definitions
32    }
33
34    /// Reads the column named `key`, or `None` if this row has no such column.
35    pub fn get(&self, key: &str) -> crate::Result<Option<Value>> {
36        match self.field_definitions.iter().position(|i| i.name == key) {
37            Some(index) => self.get_at(index),
38            None => Ok(None),
39        }
40    }
41
42    /// Reads the column at `index`, or `None` if this row has no such column.
43    ///
44    /// Unlike [`Row::get`] this works for columns that carry no TTYPEn name, and
45    /// distinguishes columns that share one.
46    pub fn get_at(&self, index: usize) -> crate::Result<Option<Value>> {
47        let Some(field) = self.field_definitions.get(index) else {
48            return Ok(None);
49        };
50
51        Ok(Some(field.decode(self.data, self.heap)?))
52    }
53}
54
55#[cfg(feature = "serde")]
56impl RowColumns for Row<'_> {
57    fn column_count(&self) -> usize {
58        self.field_definitions.len()
59    }
60
61    fn column_name(&self, index: usize) -> Option<&str> {
62        self.field_definitions
63            .get(index)
64            .map(|field| field.name.as_str())
65    }
66
67    fn column_description(&self, index: usize) -> Option<String> {
68        self.field_definitions
69            .get(index)
70            .map(|field| format!("{:?}", field.format))
71    }
72
73    fn value_at(&self, index: usize) -> crate::Result<Option<Value>> {
74        self.get_at(index)
75    }
76
77    fn column_dimensions(&self, index: usize) -> &[usize] {
78        self.field_definitions
79            .get(index)
80            .map(|field| field.dimensions.as_slice())
81            .unwrap_or_default()
82    }
83}