#[cfg(test)]
mod tests;
use crate::{db::query::construction::ConstructionBudget, error::InternalError, value::Value};
use icydb_diagnostic_code::DiagnosticExecutionBudgetResource as Resource;
use std::borrow::Borrow;
impl dyn ConstructionBudget + '_ {
pub(in crate::db) fn values_equal(
&self,
left: &Value,
right: &Value,
) -> Result<bool, InternalError> {
self.admit_value_comparison(left)?;
Ok(left == right)
}
pub(in crate::db) fn value_slices_equal<T: Borrow<Value>>(
&self,
left: &[T],
right: &[T],
) -> Result<bool, InternalError> {
if left.len() != right.len() {
return Ok(false);
}
for (left, right) in left.iter().zip(right) {
if !self.values_equal(left.borrow(), right.borrow())? {
return Ok(false);
}
}
Ok(true)
}
pub(in crate::db) fn admit_value_comparison(&self, value: &Value) -> Result<(), InternalError> {
self.charge(Resource::NestedValueSteps, 2)?;
let bytes = match value {
Value::Text(text) => text.len() as u64,
Value::Blob(blob) => blob.len() as u64,
Value::IntBig(integer) => integer.magnitude_bits().div_ceil(64).saturating_mul(8),
Value::NatBig(integer) => integer.magnitude_bits().div_ceil(64).saturating_mul(8),
Value::List(values) => {
for value in values {
self.admit_value_comparison(value)?;
}
0
}
Value::Map(entries) => {
for (key, value) in entries {
self.admit_value_comparison(key)?;
self.admit_value_comparison(value)?;
}
0
}
Value::Enum(value) => {
if let Some(payload) = value.payload() {
self.admit_value_comparison(payload)?;
}
0
}
Value::Account(_)
| Value::Bool(_)
| Value::Date(_)
| Value::Decimal(_)
| Value::Duration(_)
| Value::Float32(_)
| Value::Float64(_)
| Value::Int64(_)
| Value::Int128(_)
| Value::Nat64(_)
| Value::Nat128(_)
| Value::Null
| Value::Principal(_)
| Value::Subaccount(_)
| Value::Timestamp(_)
| Value::U256(_)
| Value::Ulid(_)
| Value::Unit => 0,
};
self.charge(Resource::PredicateExpressionSteps, bytes)
}
}