avila_arrow/
datatypes.rs

1//! Data types for avila-arrow
2
3use std::fmt;
4
5/// Arrow data type
6#[derive(Debug, Clone, PartialEq)]
7pub enum DataType {
8    /// Boolean (true/false)
9    Boolean,
10    /// 8-bit signed integer
11    Int8,
12    /// 16-bit signed integer
13    Int16,
14    /// 32-bit signed integer
15    Int32,
16    /// 64-bit signed integer
17    Int64,
18    /// 8-bit unsigned integer
19    UInt8,
20    /// 16-bit unsigned integer
21    UInt16,
22    /// 32-bit unsigned integer
23    UInt32,
24    /// 64-bit unsigned integer
25    UInt64,
26    /// 32-bit floating point
27    Float32,
28    /// 64-bit floating point
29    Float64,
30    /// UTF-8 encoded string
31    Utf8,
32    /// Binary data
33    Binary,
34    /// Timestamp (microseconds since epoch)
35    Timestamp,
36    /// Quaternion (w, x, y, z) - 4D rotation
37    Quaternion,
38    /// Tensor4D (4x4 matrix) - Spacetime tensor
39    Tensor4D,
40    /// Complex number (real, imaginary)
41    Complex64,
42    /// Spinor (2 complex components) - Particle physics
43    Spinor,
44}
45
46impl fmt::Display for DataType {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        match self {
49            DataType::Boolean => write!(f, "Boolean"),
50            DataType::Int8 => write!(f, "Int8"),
51            DataType::Int16 => write!(f, "Int16"),
52            DataType::Int32 => write!(f, "Int32"),
53            DataType::Int64 => write!(f, "Int64"),
54            DataType::UInt8 => write!(f, "UInt8"),
55            DataType::UInt16 => write!(f, "UInt16"),
56            DataType::UInt32 => write!(f, "UInt32"),
57            DataType::UInt64 => write!(f, "UInt64"),
58            DataType::Float32 => write!(f, "Float32"),
59            DataType::Float64 => write!(f, "Float64"),
60            DataType::Utf8 => write!(f, "Utf8"),
61            DataType::Binary => write!(f, "Binary"),
62            DataType::Timestamp => write!(f, "Timestamp"),
63            DataType::Quaternion => write!(f, "Quaternion"),
64            DataType::Tensor4D => write!(f, "Tensor4D"),
65            DataType::Complex64 => write!(f, "Complex64"),
66            DataType::Spinor => write!(f, "Spinor"),
67        }
68    }
69}
70
71/// Field in a schema
72#[derive(Debug, Clone, PartialEq)]
73pub struct Field {
74    name: String,
75    data_type: DataType,
76    nullable: bool,
77}
78
79impl Field {
80    /// Create a new field
81    pub fn new(name: impl Into<String>, data_type: DataType) -> Self {
82        Self {
83            name: name.into(),
84            data_type,
85            nullable: true,
86        }
87    }
88
89    /// Create a non-nullable field
90    pub fn new_non_nullable(name: impl Into<String>, data_type: DataType) -> Self {
91        Self {
92            name: name.into(),
93            data_type,
94            nullable: false,
95        }
96    }
97
98    /// Get field name
99    pub fn name(&self) -> &str {
100        &self.name
101    }
102
103    /// Get data type
104    pub fn data_type(&self) -> &DataType {
105        &self.data_type
106    }
107
108    /// Check if field is nullable
109    pub fn is_nullable(&self) -> bool {
110        self.nullable
111    }
112}
113
114/// Schema defining structure of data
115#[derive(Debug, Clone, PartialEq)]
116pub struct Schema {
117    fields: Vec<Field>,
118}
119
120impl Schema {
121    /// Create a new schema
122    pub fn new(fields: Vec<Field>) -> Self {
123        Self { fields }
124    }
125
126    /// Get number of fields
127    pub fn num_fields(&self) -> usize {
128        self.fields.len()
129    }
130
131    /// Get field by index
132    pub fn field(&self, index: usize) -> Option<&Field> {
133        self.fields.get(index)
134    }
135
136    /// Get field by name
137    pub fn field_by_name(&self, name: &str) -> Option<&Field> {
138        self.fields.iter().find(|f| f.name() == name)
139    }
140
141    /// Get all fields
142    pub fn fields(&self) -> &[Field] {
143        &self.fields
144    }
145
146    /// Get field index by name
147    pub fn index_of(&self, name: &str) -> Option<usize> {
148        self.fields.iter().position(|f| f.name() == name)
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155
156    #[test]
157    fn test_field_creation() {
158        let field = Field::new("id", DataType::Int64);
159        assert_eq!(field.name(), "id");
160        assert_eq!(field.data_type(), &DataType::Int64);
161        assert!(field.is_nullable());
162    }
163
164    #[test]
165    fn test_non_nullable_field() {
166        let field = Field::new_non_nullable("id", DataType::Int64);
167        assert!(!field.is_nullable());
168    }
169
170    #[test]
171    fn test_schema_creation() {
172        let schema = Schema::new(vec![
173            Field::new("id", DataType::Int64),
174            Field::new("value", DataType::Float64),
175        ]);
176
177        assert_eq!(schema.num_fields(), 2);
178        assert_eq!(schema.field(0).unwrap().name(), "id");
179        assert_eq!(schema.field(1).unwrap().name(), "value");
180    }
181
182    #[test]
183    fn test_schema_field_by_name() {
184        let schema = Schema::new(vec![
185            Field::new("id", DataType::Int64),
186            Field::new("value", DataType::Float64),
187        ]);
188
189        let field = schema.field_by_name("value").unwrap();
190        assert_eq!(field.data_type(), &DataType::Float64);
191    }
192
193    #[test]
194    fn test_schema_index_of() {
195        let schema = Schema::new(vec![
196            Field::new("id", DataType::Int64),
197            Field::new("value", DataType::Float64),
198        ]);
199
200        assert_eq!(schema.index_of("id"), Some(0));
201        assert_eq!(schema.index_of("value"), Some(1));
202        assert_eq!(schema.index_of("unknown"), None);
203    }
204
205    #[test]
206    fn test_datatype_display() {
207        assert_eq!(DataType::Int64.to_string(), "Int64");
208        assert_eq!(DataType::Quaternion.to_string(), "Quaternion");
209        assert_eq!(DataType::Tensor4D.to_string(), "Tensor4D");
210    }
211}