use crate::{
db::executor::{OrderReadableRow, budget::runtime_value_work},
value::Value,
};
use std::{borrow::Cow, rc::Rc};
#[derive(Clone, Debug)]
pub(in crate::db::executor) struct RetainedSlotLayout {
data: Rc<RetainedSlotLayoutData>,
}
#[derive(Debug)]
struct RetainedSlotLayoutData {
required_slots: Box<[usize]>,
value_modes: Box<[RetainedSlotValueMode]>,
slot_to_value_index: Box<[Option<usize>]>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db::executor) enum RetainedSlotValueMode {
Normal,
ScalarOctetLength,
}
impl RetainedSlotLayout {
#[must_use]
pub(in crate::db::executor) fn compile(slot_count: usize, required_slots: Vec<usize>) -> Self {
Self::compile_with_value_modes(slot_count, required_slots, Vec::new())
}
#[must_use]
pub(in crate::db::executor) fn compile_with_value_modes(
slot_count: usize,
required_slots: Vec<usize>,
value_modes: Vec<RetainedSlotValueMode>,
) -> Self {
debug_assert!(value_modes.is_empty() || required_slots.len() == value_modes.len());
let mut has_value_mode_overrides = false;
for mode in &value_modes {
has_value_mode_overrides |= *mode != RetainedSlotValueMode::Normal;
}
let mut slot_to_value_index = vec![None; slot_count];
for (value_index, &slot) in required_slots.iter().enumerate() {
if let Some(entry) = slot_to_value_index.get_mut(slot) {
*entry = Some(value_index);
}
}
Self {
data: Rc::new(RetainedSlotLayoutData {
required_slots: required_slots.into_boxed_slice(),
value_modes: if has_value_mode_overrides {
value_modes.into_boxed_slice()
} else {
Vec::new().into_boxed_slice()
},
slot_to_value_index: slot_to_value_index.into_boxed_slice(),
}),
}
}
#[must_use]
pub(in crate::db::executor) fn required_slots(&self) -> &[usize] {
self.data.required_slots.as_ref()
}
#[must_use]
pub(in crate::db::executor) fn override_value_modes(&self) -> Option<&[RetainedSlotValueMode]> {
self.has_value_mode_overrides()
.then_some(self.data.value_modes.as_ref())
}
#[must_use]
pub(in crate::db::executor) fn has_value_mode_overrides(&self) -> bool {
!self.data.value_modes.is_empty()
}
#[must_use]
pub(in crate::db::executor) fn value_index_for_slot(&self, slot: usize) -> Option<usize> {
self.data.slot_to_value_index.get(slot).copied().flatten()
}
#[must_use]
pub(in crate::db::executor) fn retained_value_count(&self) -> usize {
self.data.required_slots.len()
}
}
pub(in crate::db) struct RetainedSlotRow {
layout: RetainedSlotLayout,
values: Vec<Option<Value>>,
}
impl RetainedSlotRow {
#[must_use]
pub(in crate::db::executor) fn from_indexed_values(
layout: &RetainedSlotLayout,
values: Vec<Option<Value>>,
) -> Self {
debug_assert_eq!(values.len(), layout.retained_value_count());
Self {
layout: layout.clone(),
values,
}
}
#[must_use]
pub(in crate::db) fn slot_ref(&self, slot: usize) -> Option<&Value> {
let index = self.layout.value_index_for_slot(slot)?;
self.values.get(index).and_then(Option::as_ref)
}
pub(in crate::db) fn take_slot(&mut self, slot: usize) -> Option<Value> {
let index = self.layout.value_index_for_slot(slot)?;
self.values.get_mut(index)?.take()
}
#[must_use]
pub(in crate::db::executor) fn estimated_backing_bytes(&self) -> u64 {
self.values.iter().flatten().fold(0_u64, |total, value| {
total.saturating_add(runtime_value_work(value).0)
})
}
}
impl OrderReadableRow for RetainedSlotRow {
fn read_order_slot_ref(&self, slot: usize) -> Option<&Value> {
self.slot_ref(slot)
}
fn read_order_slot_cow(&self, slot: usize) -> Option<Cow<'_, Value>> {
self.slot_ref(slot).map(Cow::Borrowed)
}
fn order_slots_are_borrowed(&self) -> bool {
true
}
}
crate::retained::retained_fields!(RetainedSlotLayout {
Self{data} => [data],
});
crate::retained::retained_fields!(RetainedSlotLayoutData {
Self{required_slots,value_modes,slot_to_value_index} => [required_slots,value_modes,slot_to_value_index],
});
crate::retained::retained_copy!(RetainedSlotValueMode);