use crate::arrow_properties::serialize_property_set_to_jsonb;
use crate::properties::property_set::PropertySet;
use anyhow::Result;
use datafusion::arrow::array::{BinaryArray, DictionaryArray, Int32Array};
use datafusion::arrow::datatypes::Int32Type;
use datafusion::common::DataFusionError;
use micromegas_transit::value::Object;
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct ObjectPointer(*const Object);
unsafe impl Send for ObjectPointer {}
unsafe impl Sync for ObjectPointer {}
impl ObjectPointer {
fn new(arc_obj: &Arc<Object>) -> Self {
Self(Arc::as_ptr(arc_obj))
}
}
pub struct PropertySetJsonbDictionaryBuilder {
pointer_to_index: HashMap<ObjectPointer, i32>,
jsonb_values: Vec<Vec<u8>>,
keys: Vec<Option<i32>>,
_property_refs: Vec<Arc<Object>>,
}
impl PropertySetJsonbDictionaryBuilder {
pub fn new(capacity: usize) -> Self {
Self {
pointer_to_index: HashMap::with_capacity(capacity),
jsonb_values: Vec::with_capacity(capacity),
keys: Vec::with_capacity(capacity),
_property_refs: Vec::with_capacity(capacity),
}
}
pub fn append_property_set(&mut self, property_set: &PropertySet) -> Result<()> {
let arc_obj = property_set.as_arc_object();
let ptr = ObjectPointer::new(arc_obj);
match self.pointer_to_index.get(&ptr) {
Some(&index) => {
self.keys.push(Some(index));
}
None => {
let jsonb_bytes = serialize_property_set_to_jsonb(property_set)?;
let new_index = self.jsonb_values.len() as i32;
self.jsonb_values.push(jsonb_bytes);
self.pointer_to_index.insert(ptr, new_index);
self.keys.push(Some(new_index));
self._property_refs.push(Arc::clone(arc_obj));
}
}
Ok(())
}
pub fn append_null(&mut self) {
self.keys.push(None);
}
pub fn finish(self) -> Result<DictionaryArray<Int32Type>> {
let keys = Int32Array::from(self.keys);
let byte_slices: Vec<&[u8]> = self.jsonb_values.iter().map(|v| v.as_slice()).collect();
let values = Arc::new(BinaryArray::from_vec(byte_slices));
DictionaryArray::try_new(keys, values)
.map_err(|e| DataFusionError::ArrowError(Box::new(e), None).into())
}
pub fn len(&self) -> usize {
self.keys.len()
}
pub fn is_empty(&self) -> bool {
self.keys.is_empty()
}
}