use std::fmt::Display;
use std::fmt::Formatter;
use std::hash::Hasher;
use std::sync::Arc;
use vortex_error::VortexExpect;
use vortex_error::VortexResult;
use vortex_error::vortex_ensure;
use crate::ArrayEq;
use crate::ArrayHash;
use crate::ArrayRef;
use crate::ArraySlots;
use crate::EqMode;
use crate::IntoArray;
use crate::array::Array;
use crate::array::ArrayParts;
use crate::array::TypedArrayRef;
use crate::array_slots;
use crate::arrays::ListView;
use crate::arrays::ListViewArray;
use crate::arrays::listview::ListViewArrayExt;
use crate::arrays::map::Map;
use crate::dtype::DType;
use crate::dtype::MapDType;
use crate::validity::Validity;
#[array_slots(Map)]
pub struct MapSlots {
#[slot(0)]
pub entries: ArrayRef,
}
#[derive(Clone, Debug, Default)]
pub struct MapData;
impl Display for MapData {
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
impl ArrayEq for MapData {
fn array_eq(&self, _other: &Self, _accuracy: EqMode) -> bool {
true
}
}
impl ArrayHash for MapData {
fn array_hash<H: Hasher>(&self, _state: &mut H, _accuracy: EqMode) {}
}
impl MapData {
pub(crate) fn make_slots(entries: ArrayRef) -> ArraySlots {
MapSlots { entries }.into_slots()
}
}
pub struct MapDataParts {
pub map_dtype: MapDType,
pub entries: ListViewArray,
}
pub trait MapArrayExt: MapArraySlotsExt {
fn entries_at(&self, index: usize) -> VortexResult<ArrayRef> {
self.entries().as_::<ListView>().list_elements_at(index)
}
fn entry_count_at(&self, index: usize) -> usize {
self.entries().as_::<ListView>().size_at(index)
}
fn map_validity(&self) -> Validity {
self.entries().as_::<ListView>().listview_validity()
}
fn map_dtype(&self) -> &MapDType {
self.as_ref()
.dtype()
.as_map_opt()
.vortex_expect("MapArray requires a map dtype")
}
fn keys_sorted(&self) -> bool {
self.map_dtype().keys_sorted()
}
}
impl<T: TypedArrayRef<Map>> MapArrayExt for T {}
impl Array<Map> {
pub fn new(map_dtype: MapDType, entries: ListViewArray) -> Self {
Self::try_new(map_dtype, entries).vortex_expect("MapArray construction failed")
}
pub fn try_new(map_dtype: MapDType, entries: ListViewArray) -> VortexResult<Self> {
let nullability = entries.nullability();
let dtype = DType::Map(map_dtype, nullability);
let len = entries.len();
let slots = MapData::make_slots(entries.into_array());
let parts = ArrayParts::new(Map, dtype, len, MapData).with_slots(slots);
Self::try_from_parts(parts)
}
pub unsafe fn new_unchecked(map_dtype: MapDType, entries: ListViewArray) -> Self {
let nullability = entries.nullability();
let dtype = DType::Map(map_dtype, nullability);
let len = entries.len();
let slots = MapData::make_slots(entries.into_array());
let parts = ArrayParts::new(Map, dtype, len, MapData).with_slots(slots);
unsafe { Self::from_parts_unchecked(parts) }
}
pub fn into_data_parts(self) -> MapDataParts {
let map_dtype = self
.dtype()
.as_map_opt()
.vortex_expect("MapArray requires a map dtype")
.clone();
let entries = self.entries().clone().downcast::<ListView>();
MapDataParts { map_dtype, entries }
}
}
fn expected_entries_dtype(map_dtype: &MapDType, nullability: crate::dtype::Nullability) -> DType {
DType::List(Arc::new(map_dtype.entries_dtype()), nullability)
}
pub(super) fn validate_entries(
map_dtype: &MapDType,
nullability: crate::dtype::Nullability,
len: usize,
entries: &ArrayRef,
) -> VortexResult<()> {
vortex_ensure!(
entries.is::<ListView>(),
"MapArray entries must use vortex.listview encoding, got {}",
entries.encoding_id()
);
vortex_ensure!(
entries.len() == len,
"MapArray entries length {} does not match outer length {len}",
entries.len()
);
let expected_dtype = expected_entries_dtype(map_dtype, nullability);
vortex_ensure!(
entries.dtype() == &expected_dtype,
"MapArray entries dtype {} does not match expected {expected_dtype}",
entries.dtype()
);
Ok(())
}