use std::collections::HashSet;
use std::hash::{Hash, Hasher};
use std::sync::{Arc, RwLock};
use crate::types::array::Array;
use crate::types::function::Function;
use crate::types::map::Map;
use crate::types::range::Range;
use crate::types::struct_type::Struct;
use crate::types::tuple::Tuple;
use crate::types::Type;
#[derive(Debug, Clone)]
struct InternedString(Arc<str>);
impl Hash for InternedString {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.as_ref().hash(state);
}
}
impl PartialEq for InternedString {
fn eq(&self, other: &Self) -> bool {
self.0.as_ref() == other.0.as_ref()
}
}
impl Eq for InternedString {}
impl std::borrow::Borrow<str> for InternedString {
fn borrow(&self) -> &str {
self.0.as_ref()
}
}
#[derive(Debug, Clone)]
struct InternedType(Arc<Type>);
impl Hash for InternedType {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.as_ref().hash(state);
}
}
impl PartialEq for InternedType {
fn eq(&self, other: &Self) -> bool {
self.0.as_ref() == other.0.as_ref()
}
}
impl Eq for InternedType {}
impl std::borrow::Borrow<Type> for InternedType {
fn borrow(&self) -> &Type {
self.0.as_ref()
}
}
#[derive(Debug, Default)]
pub struct Interner {
strings: RwLock<HashSet<InternedString>>,
types: RwLock<HashSet<InternedType>>,
}
impl Interner {
pub fn new() -> Self {
Self {
strings: RwLock::new(HashSet::new()),
types: RwLock::new(HashSet::new()),
}
}
pub fn intern(&self, s: &str) -> Arc<str> {
{
let strings = self.strings.read().expect("interner lock poisoned");
if let Some(existing) = strings.get(s) {
return existing.0.clone();
}
}
let mut strings = self.strings.write().expect("interner lock poisoned");
if let Some(existing) = strings.get(s) {
return existing.0.clone();
}
let arc: Arc<str> = Arc::from(s);
strings.insert(InternedString(arc.clone()));
arc
}
pub fn intern_type(&self, t: Type) -> Arc<Type> {
self.intern_type_arc(Arc::new(t))
}
fn intern_type_arc(&self, arc: Arc<Type>) -> Arc<Type> {
let interned = match arc.as_ref() {
Type::Binary
| Type::Boolean
| Type::Interval
| Type::CalendarInterval
| Type::Int
| Type::Double
| Type::Rows
| Type::String
| Type::Timestamp
| Type::Unknown
| Type::Decimal(_)
| Type::Variant => return self.intern_type_inner_arc(arc),
Type::Array(arr) => {
let elem = self.intern_type_arc(arr.element_type.clone());
Array { element_type: elem }.into()
}
Type::Map(map) => {
let key = self.intern_type_arc(map.key_type.clone());
let val = self.intern_type_arc(map.value_type.clone());
Map {
key_type: key,
value_type: val,
}
.into()
}
Type::Range(range) => {
let of = self.intern_type_arc(range.of.clone());
Range { of }.into()
}
Type::Tuple(tuple) => {
let elements = tuple
.elements
.iter()
.map(|e| self.intern_type_arc(e.clone()))
.collect();
Tuple { elements }.into()
}
Type::Function(func) => {
let params = func
.params
.iter()
.map(|p| self.intern_type_arc(p.clone()))
.collect();
let ret = self.intern_type_arc(func.return_type.clone());
Function {
params,
return_type: ret,
}
.into()
}
Type::Struct(s) => {
let fields: Vec<_> = s
.iter_arc()
.map(|(k, v)| (k.clone(), self.intern_type_arc(v.clone())))
.collect();
Struct::from_arc_iter(fields).into()
}
};
self.intern_type_inner(interned)
}
fn intern_type_inner(&self, t: Type) -> Arc<Type> {
self.intern_type_inner_arc(Arc::new(t))
}
fn intern_type_inner_arc(&self, arc: Arc<Type>) -> Arc<Type> {
{
let types = self.types.read().expect("interner lock poisoned");
if let Some(existing) = types.get(arc.as_ref()) {
return existing.0.clone();
}
}
let mut types = self.types.write().expect("interner lock poisoned");
if let Some(existing) = types.get(arc.as_ref()) {
return existing.0.clone();
}
types.insert(InternedType(arc.clone()));
arc
}
pub fn len(&self) -> usize {
self.strings.read().expect("interner lock poisoned").len()
}
pub fn is_empty(&self) -> bool {
self.strings
.read()
.expect("interner lock poisoned")
.is_empty()
}
pub fn type_count(&self) -> usize {
self.types.read().expect("interner lock poisoned").len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_intern_returns_same_arc() {
let interner = Interner::new();
let a1 = interner.intern("hello");
let a2 = interner.intern("hello");
assert!(Arc::ptr_eq(&a1, &a2));
}
#[test]
fn test_intern_different_strings() {
let interner = Interner::new();
let a = interner.intern("hello");
let b = interner.intern("world");
assert!(!Arc::ptr_eq(&a, &b));
assert_eq!(&*a, "hello");
assert_eq!(&*b, "world");
}
#[test]
fn test_intern_count() {
let interner = Interner::new();
assert_eq!(interner.len(), 0);
assert!(interner.is_empty());
interner.intern("a");
assert_eq!(interner.len(), 1);
interner.intern("b");
assert_eq!(interner.len(), 2);
interner.intern("a");
assert_eq!(interner.len(), 2);
}
#[test]
fn test_intern_type_returns_same_arc() {
let interner = Interner::new();
let t1 = interner.intern_type(Type::String);
let t2 = interner.intern_type(Type::String);
assert!(Arc::ptr_eq(&t1, &t2));
}
#[test]
fn test_intern_type_different_types() {
let interner = Interner::new();
let t1 = interner.intern_type(Type::String);
let t2 = interner.intern_type(Type::Int);
assert!(!Arc::ptr_eq(&t1, &t2));
}
#[test]
fn test_intern_type_compound_shares_children() {
let interner = Interner::new();
let arr = interner.intern_type(Array::new(Type::String).into());
let string = interner.intern_type(Type::String);
if let Type::Array(a) = arr.as_ref() {
assert!(Arc::ptr_eq(&a.element_type, &string));
} else {
panic!("expected Array type");
}
}
#[test]
fn test_intern_type_count() {
let interner = Interner::new();
assert_eq!(interner.type_count(), 0);
interner.intern_type(Type::String);
assert_eq!(interner.type_count(), 1);
interner.intern_type(Type::String);
assert_eq!(interner.type_count(), 1);
interner.intern_type(Array::new(Type::String).into());
assert_eq!(interner.type_count(), 2);
}
}