use crate::ko::errors::DataSectionParseError;
use crate::ko::SectionIdx;
use crate::{BufferIterator, FromBytes, KOSValue, ToBytes, WritableBuffer};
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::slice::Iter;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct DataIdx(u32);
impl From<usize> for DataIdx {
fn from(i: usize) -> Self {
Self(i as u32)
}
}
impl From<u8> for DataIdx {
fn from(i: u8) -> Self {
Self(i as u32)
}
}
impl From<u16> for DataIdx {
fn from(i: u16) -> Self {
Self(i as u32)
}
}
impl From<u32> for DataIdx {
fn from(i: u32) -> Self {
Self(i)
}
}
impl From<DataIdx> for u32 {
fn from(data_idx: DataIdx) -> Self {
data_idx.0
}
}
impl From<DataIdx> for usize {
fn from(data_idx: DataIdx) -> Self {
data_idx.0 as usize
}
}
impl DataIdx {
pub const PLACEHOLDER: DataIdx = DataIdx(u32::MAX);
}
#[derive(Debug)]
pub struct DataSection {
map: HashMap<u64, usize>,
data: Vec<KOSValue>,
size: u32,
section_index: SectionIdx,
}
impl DataSection {
pub fn new(section_index: SectionIdx) -> Self {
Self {
map: HashMap::new(),
data: Vec::new(),
size: 0,
section_index,
}
}
pub fn with_capacity(amount: usize, section_index: SectionIdx) -> Self {
Self {
map: HashMap::with_capacity(amount),
data: Vec::with_capacity(amount),
size: 0,
section_index,
}
}
pub fn position(&self, value: &KOSValue) -> Option<DataIdx> {
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
let hash = hasher.finish();
self.map
.get(&hash)
.cloned()
.map(|v| DataIdx::from(v as u32))
}
pub fn add_checked(&mut self, value: KOSValue) -> DataIdx {
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
let hash = hasher.finish();
if let Some(i) = self.map.get(&hash) {
DataIdx::from(*i)
} else {
self.size += value.size_bytes() as u32;
let index = self.data.len();
self.map.insert(hash, index);
self.data.push(value);
DataIdx::from(index)
}
}
pub fn add(&mut self, value: KOSValue) -> DataIdx {
self.size += value.size_bytes() as u32;
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
let hash = hasher.finish();
self.map.insert(hash, self.data.len());
self.data.push(value);
DataIdx::from(self.data.len() - 1)
}
pub fn get(&self, index: DataIdx) -> Option<&KOSValue> {
self.data.get(usize::from(index))
}
pub fn data(&self) -> Iter<KOSValue> {
self.data.iter()
}
pub fn size(&self) -> u32 {
self.size
}
pub fn section_index(&self) -> SectionIdx {
self.section_index
}
pub fn parse(
source: &mut BufferIterator,
size: u32,
section_index: SectionIdx,
) -> Result<Self, DataSectionParseError> {
let mut bytes_read = 0;
let mut data = Vec::new();
let mut map = HashMap::new();
while bytes_read < size as usize {
let kos_value = KOSValue::from_bytes(source).map_err(|e| {
DataSectionParseError::KOSValueParseError(source.current_index(), e)
})?;
bytes_read += kos_value.size_bytes() as usize;
let mut hasher = DefaultHasher::new();
kos_value.hash(&mut hasher);
let hash = hasher.finish();
map.insert(hash, data.len());
data.push(kos_value);
}
Ok(Self {
map,
data,
size,
section_index,
})
}
pub fn write(&self, buf: &mut impl WritableBuffer) {
for value in self.data.iter() {
value.to_bytes(buf);
}
}
}
#[cfg(test)]
impl PartialEq for DataSection {
fn eq(&self, other: &Self) -> bool {
if self.data().count() != other.data().count() {
return false;
}
for (r, h) in self.data().zip(other.data()) {
if r != h {
return false;
}
}
true
}
}