use std::collections::HashMap;
use crate::tile::PropKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InferredKind {
Unknown,
Bool,
I64,
U64,
F32,
F64,
Str,
}
impl InferredKind {
#[must_use]
pub fn merge(self, other: Self) -> Self {
if self == Self::Unknown {
return other;
}
if other == Self::Unknown || self == other {
return self;
}
#[expect(clippy::match_same_arms)]
match (self, other) {
(Self::I64 | Self::U64, Self::I64 | Self::U64) => Self::I64,
(Self::F32 | Self::F64, Self::F32 | Self::F64) => Self::F64,
(Self::I64 | Self::U64, Self::F32 | Self::F64)
| (Self::F32 | Self::F64, Self::I64 | Self::U64) => Self::F64,
_ => Self::Str,
}
}
#[must_use]
pub fn prop_kind(self) -> PropKind {
match self {
Self::Unknown | Self::Str => PropKind::Str,
Self::Bool => PropKind::Bool,
Self::I64 => PropKind::I64,
Self::U64 => PropKind::U64,
Self::F32 => PropKind::F32,
Self::F64 => PropKind::F64,
}
}
}
#[derive(Default)]
pub(crate) struct ColumnInference<'a> {
index: HashMap<&'a str, usize>,
names: Vec<String>,
kinds: Vec<InferredKind>,
}
impl<'a> ColumnInference<'a> {
pub fn observe(&mut self, name: &'a str, kind: InferredKind) -> usize {
let idx = self.column(name);
self.merge(idx, kind);
idx
}
pub fn column(&mut self, name: &'a str) -> usize {
*self.index.entry(name).or_insert_with(|| {
self.names.push(name.to_string());
self.kinds.push(InferredKind::Unknown);
self.names.len() - 1
})
}
pub fn merge(&mut self, idx: usize, kind: InferredKind) {
let slot = &mut self.kinds[idx];
*slot = slot.merge(kind);
}
pub fn finish(self) -> (Vec<String>, Vec<PropKind>) {
let kinds = self
.kinds
.into_iter()
.map(InferredKind::prop_kind)
.collect();
(self.names, kinds)
}
}