use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DataType {
Boolean,
Int8,
UInt8,
Int16,
UInt16,
Int32,
UInt32,
Int64,
UInt64,
Float32,
Float64,
String,
Binary,
Date,
Timestamp,
FixedBinary(usize),
Decimal(usize, usize),
}
impl DataType {
pub fn size(&self) -> Option<usize> {
match self {
DataType::Boolean => Some(1),
DataType::Int8 => Some(1),
DataType::UInt8 => Some(1),
DataType::Int16 => Some(2),
DataType::UInt16 => Some(2),
DataType::Int32 => Some(4),
DataType::UInt32 => Some(4),
DataType::Int64 => Some(8),
DataType::UInt64 => Some(8),
DataType::Float32 => Some(4),
DataType::Float64 => Some(8),
DataType::String => None,
DataType::Binary => None,
DataType::Date => Some(4),
DataType::Timestamp => Some(8),
DataType::FixedBinary(size) => Some(*size),
DataType::Decimal(_, _) => Some(16),
}
}
pub fn is_numeric(&self) -> bool {
matches!(
self,
DataType::Int8
| DataType::UInt8
| DataType::Int16
| DataType::UInt16
| DataType::Int32
| DataType::UInt32
| DataType::Int64
| DataType::UInt64
| DataType::Float32
| DataType::Float64
| DataType::Decimal(_, _)
)
}
pub fn is_integer(&self) -> bool {
matches!(
self,
DataType::Int8
| DataType::UInt8
| DataType::Int16
| DataType::UInt16
| DataType::Int32
| DataType::UInt32
| DataType::Int64
| DataType::UInt64
)
}
pub fn is_float(&self) -> bool {
matches!(self, DataType::Float32 | DataType::Float64)
}
pub fn is_variable_length(&self) -> bool {
matches!(self, DataType::String | DataType::Binary)
}
}
#[derive(Debug, Clone)]
pub struct Field {
pub name: String,
pub data_type: DataType,
pub nullable: bool,
pub default_value: Option<Vec<u8>>,
pub metadata: HashMap<String, String>,
}
impl Field {
pub fn new(name: &str, data_type: DataType, nullable: bool) -> Self {
Field {
name: name.to_string(),
data_type,
nullable,
default_value: None,
metadata: HashMap::new(),
}
}
pub fn with_default(name: &str, data_type: DataType, nullable: bool, default_value: Vec<u8>) -> Self {
Field {
name: name.to_string(),
data_type,
nullable,
default_value: Some(default_value),
metadata: HashMap::new(),
}
}
pub fn with_metadata(mut self, key: &str, value: &str) -> Self {
self.metadata.insert(key.to_string(), value.to_string());
self
}
}
#[derive(Debug, Clone)]
pub struct Schema {
pub fields: Vec<Field>,
pub field_indices: HashMap<String, usize>,
pub metadata: HashMap<String, String>,
}
impl Schema {
pub fn new(fields: Vec<Field>) -> Self {
let mut field_indices = HashMap::new();
for (i, field) in fields.iter().enumerate() {
field_indices.insert(field.name.clone(), i);
}
Schema {
fields,
field_indices,
metadata: HashMap::new(),
}
}
pub fn with_metadata(mut self, key: &str, value: &str) -> Self {
self.metadata.insert(key.to_string(), value.to_string());
self
}
pub fn field(&self, name: &str) -> Option<&Field> {
self.field_indices.get(name).map(|&i| &self.fields[i])
}
pub fn field_by_index(&self, index: usize) -> Option<&Field> {
self.fields.get(index)
}
pub fn field_index(&self, name: &str) -> Option<usize> {
self.field_indices.get(name).copied()
}
pub fn field_count(&self) -> usize {
self.fields.len()
}
pub fn contains_field(&self, name: &str) -> bool {
self.field_indices.contains_key(name)
}
}