use crate::{
db::{
codec::serialize_row_payload,
data::{
CanonicalRow, RawRow, StructuralFieldDecodeContract, StructuralRowContract,
accepted_kind_supports_storage_key_binary, decode_storage_key_binary_value_bytes,
decode_structural_field_by_accepted_kind_bytes, decode_structural_field_by_kind_bytes,
decode_structural_value_storage_bytes, encode_storage_key_binary_value_bytes,
encode_structural_field_by_accepted_kind_bytes, encode_structural_field_by_kind_bytes,
encode_structural_value_storage_bytes, encode_structural_value_storage_null_bytes,
supports_storage_key_binary_kind, validate_storage_key_binary_value_bytes,
validate_structural_field_by_accepted_kind_bytes,
validate_structural_field_by_kind_bytes, validate_structural_value_storage_bytes,
value_storage_bytes_are_null,
},
schema::{AcceptedFieldDecodeContract, PersistedFieldKind},
},
error::InternalError,
model::{
entity::EntityModel,
field::{FieldModel, FieldStorageDecode, LeafCodec, ScalarCodec},
},
types::Decimal,
value::Value,
};
use std::{borrow::Cow, cmp::Ordering};
use crate::db::data::persisted_row::{
codec::{
ScalarSlotValueRef, ScalarValueRef, decode_scalar_slot_value, encode_scalar_slot_value,
},
types::generated_compatible_field_model_for_slot,
};
#[doc(hidden)]
pub fn decode_slot_into_runtime_value(
model: &'static EntityModel,
slot: usize,
raw_value: &[u8],
) -> Result<Value, InternalError> {
let field = generated_compatible_field_model_for_slot(model, slot)?;
let field = StructuralFieldDecodeContract::from_field_model(field);
decode_runtime_value_from_field_contract(field, raw_value)
}
pub(in crate::db::data::persisted_row) fn decode_runtime_value_from_field_contract(
field: StructuralFieldDecodeContract,
raw_value: &[u8],
) -> Result<Value, InternalError> {
match field.leaf_codec() {
LeafCodec::Scalar(codec) => match decode_scalar_slot_value(raw_value, codec, field.name())?
{
ScalarSlotValueRef::Null => Ok(Value::Null),
ScalarSlotValueRef::Value(value) => Ok(value.into_value()),
},
LeafCodec::StructuralFallback => decode_non_scalar_slot_value(raw_value, field),
}
}
pub(in crate::db) fn decode_runtime_value_from_accepted_field_contract(
field: AcceptedFieldDecodeContract<'_>,
raw_value: &[u8],
) -> Result<Value, InternalError> {
match field.leaf_codec() {
LeafCodec::Scalar(codec) => {
match decode_scalar_slot_value(raw_value, codec, field.field_name())? {
ScalarSlotValueRef::Null => Ok(Value::Null),
ScalarSlotValueRef::Value(value) => Ok(value.into_value()),
}
}
LeafCodec::StructuralFallback => decode_non_scalar_accepted_slot_value(raw_value, field),
}
}
pub(in crate::db) fn decode_runtime_value_from_row_contract(
contract: &StructuralRowContract,
slot: usize,
raw_value: &[u8],
) -> Result<Value, InternalError> {
if let Some(accepted_field) = contract.accepted_field_decode_contract(slot) {
return decode_runtime_value_from_accepted_field_contract(accepted_field, raw_value);
}
let field = contract.field_decode_contract(slot)?;
decode_runtime_value_from_field_contract(field, raw_value)
}
pub(in crate::db) fn decode_scalar_slot_value_from_row_contract<'raw>(
contract: &StructuralRowContract,
slot: usize,
raw_value: &'raw [u8],
accepted_non_scalar_context: &str,
generated_non_scalar_context: &str,
) -> Result<ScalarSlotValueRef<'raw>, InternalError> {
if let Some(accepted_field) = contract.accepted_field_decode_contract(slot) {
let LeafCodec::Scalar(codec) = accepted_field.leaf_codec() else {
return Err(InternalError::persisted_row_decode_failed(format!(
"{accepted_non_scalar_context}: slot={slot}",
)));
};
return decode_scalar_slot_value(raw_value, codec, accepted_field.field_name());
}
let field = contract.field_decode_contract(slot)?;
let LeafCodec::Scalar(codec) = field.leaf_codec() else {
return Err(InternalError::persisted_row_decode_failed(format!(
"{generated_non_scalar_context}: slot={slot}",
)));
};
decode_scalar_slot_value(raw_value, codec, field.name())
}
#[doc(hidden)]
pub fn encode_runtime_value_into_slot(
model: &'static EntityModel,
slot: usize,
value: &Value,
) -> Result<Vec<u8>, InternalError> {
let field = generated_compatible_field_model_for_slot(model, slot)?;
encode_runtime_value_for_field_model(field, value)
}
pub(in crate::db::data::persisted_row) fn encode_runtime_value_for_field_model(
field: &FieldModel,
value: &Value,
) -> Result<Vec<u8>, InternalError> {
let value = field
.normalize_runtime_value_for_storage(value)
.map_err(|err| InternalError::persisted_row_field_encode_failed(field.name(), err))?;
let value = value.as_ref();
field
.validate_runtime_value_for_storage(value)
.map_err(|err| InternalError::persisted_row_field_encode_failed(field.name(), err))?;
if matches!(value, Value::Null) {
return encode_null_slot_value_for_field(field);
}
match field.storage_decode() {
FieldStorageDecode::Value => encode_structural_value_storage_bytes(value)
.map_err(|err| InternalError::persisted_row_field_encode_failed(field.name(), err)),
FieldStorageDecode::ByKind => match field.leaf_codec() {
LeafCodec::Scalar(codec) => {
let scalar =
scalar_slot_value_ref_from_runtime_value(value, codec).ok_or_else(|| {
InternalError::persisted_row_field_encode_failed(
field.name(),
format!(
"field kind {:?} requires a scalar runtime value, found {value:?}",
field.kind()
),
)
})?;
Ok(encode_scalar_slot_value(scalar))
}
LeafCodec::StructuralFallback => {
if supports_storage_key_binary_kind(field.kind()) {
encode_storage_key_binary_value_bytes(field.kind(), value, field.name())?
.ok_or_else(|| {
InternalError::persisted_row_field_encode_failed(
field.name(),
"storage-key binary lane rejected a supported field kind",
)
})
} else {
encode_structural_field_by_kind_bytes(field.kind(), value, field.name())
}
}
},
}
}
pub(in crate::db) fn encode_runtime_value_for_accepted_field_contract(
field: AcceptedFieldDecodeContract<'_>,
value: &Value,
) -> Result<Vec<u8>, InternalError> {
let value = normalize_decimal_scale_for_accepted_storage(field.kind(), value)
.map_err(|err| InternalError::persisted_row_field_encode_failed(field.field_name(), err))?;
let value = value.as_ref();
if matches!(value, Value::Null) {
return encode_null_slot_value_for_accepted_field(field);
}
match field.storage_decode() {
FieldStorageDecode::Value => encode_structural_value_storage_bytes(value).map_err(|err| {
InternalError::persisted_row_field_encode_failed(field.field_name(), err)
}),
FieldStorageDecode::ByKind => match field.leaf_codec() {
LeafCodec::Scalar(codec) => {
let scalar =
scalar_slot_value_ref_from_runtime_value(value, codec).ok_or_else(|| {
InternalError::persisted_row_field_encode_failed(
field.field_name(),
format!(
"accepted field kind {:?} requires a scalar runtime value, found {value:?}",
field.kind()
),
)
})?;
Ok(encode_scalar_slot_value(scalar))
}
LeafCodec::StructuralFallback => encode_structural_field_by_accepted_kind_bytes(
field.kind(),
value,
field.field_name(),
),
},
}
}
fn encode_null_slot_value_for_field(field: &FieldModel) -> Result<Vec<u8>, InternalError> {
match field.storage_decode() {
FieldStorageDecode::Value => Ok(encode_structural_value_storage_null_bytes()),
FieldStorageDecode::ByKind => match field.leaf_codec() {
LeafCodec::Scalar(_) => Ok(encode_scalar_slot_value(ScalarSlotValueRef::Null)),
LeafCodec::StructuralFallback if supports_storage_key_binary_kind(field.kind()) => {
encode_storage_key_binary_value_bytes(field.kind(), &Value::Null, field.name())?
.ok_or_else(|| {
InternalError::persisted_row_field_encode_failed(
field.name(),
"storage-key binary lane rejected a supported field kind",
)
})
}
LeafCodec::StructuralFallback => Ok(encode_structural_value_storage_null_bytes()),
},
}
}
fn encode_null_slot_value_for_accepted_field(
field: AcceptedFieldDecodeContract<'_>,
) -> Result<Vec<u8>, InternalError> {
if !field.nullable() {
return Err(InternalError::persisted_row_field_encode_failed(
field.field_name(),
"required field cannot store null",
));
}
match field.storage_decode() {
FieldStorageDecode::Value => Ok(encode_structural_value_storage_null_bytes()),
FieldStorageDecode::ByKind => match field.leaf_codec() {
LeafCodec::Scalar(_) => Ok(encode_scalar_slot_value(ScalarSlotValueRef::Null)),
LeafCodec::StructuralFallback => encode_structural_field_by_accepted_kind_bytes(
field.kind(),
&Value::Null,
field.field_name(),
),
},
}
}
const fn scalar_slot_value_ref_from_runtime_value(
value: &Value,
codec: ScalarCodec,
) -> Option<ScalarSlotValueRef<'_>> {
let scalar = match (codec, value) {
(ScalarCodec::Blob, Value::Blob(value)) => ScalarValueRef::Blob(value.as_slice()),
(ScalarCodec::Bool, Value::Bool(value)) => ScalarValueRef::Bool(*value),
(ScalarCodec::Date, Value::Date(value)) => ScalarValueRef::Date(*value),
(ScalarCodec::Duration, Value::Duration(value)) => ScalarValueRef::Duration(*value),
(ScalarCodec::Float32, Value::Float32(value)) => ScalarValueRef::Float32(*value),
(ScalarCodec::Float64, Value::Float64(value)) => ScalarValueRef::Float64(*value),
(ScalarCodec::Int64, Value::Int(value)) => ScalarValueRef::Int(*value),
(ScalarCodec::Principal, Value::Principal(value)) => ScalarValueRef::Principal(*value),
(ScalarCodec::Subaccount, Value::Subaccount(value)) => ScalarValueRef::Subaccount(*value),
(ScalarCodec::Text, Value::Text(value)) => ScalarValueRef::Text(value.as_str()),
(ScalarCodec::Timestamp, Value::Timestamp(value)) => ScalarValueRef::Timestamp(*value),
(ScalarCodec::Uint64, Value::Uint(value)) => ScalarValueRef::Uint(*value),
(ScalarCodec::Ulid, Value::Ulid(value)) => ScalarValueRef::Ulid(*value),
(ScalarCodec::Unit, Value::Unit) => ScalarValueRef::Unit,
_ => return None,
};
Some(ScalarSlotValueRef::Value(scalar))
}
fn normalize_decimal_scale_for_accepted_storage<'a>(
kind: &PersistedFieldKind,
value: &'a Value,
) -> Result<Cow<'a, Value>, String> {
if matches!(value, Value::Null) {
return Ok(Cow::Borrowed(value));
}
match (kind, value) {
(PersistedFieldKind::Decimal { scale }, Value::Decimal(decimal)) => {
let normalized =
decimal_with_accepted_storage_scale(*decimal, *scale).ok_or_else(|| {
format!(
"decimal scale mismatch: expected {scale}, found {}",
decimal.scale()
)
})?;
if normalized.scale() == decimal.scale() {
Ok(Cow::Borrowed(value))
} else {
Ok(Cow::Owned(Value::Decimal(normalized)))
}
}
(PersistedFieldKind::Relation { key_kind, .. }, value) => {
normalize_decimal_scale_for_accepted_storage(key_kind, value)
}
(PersistedFieldKind::List(inner) | PersistedFieldKind::Set(inner), Value::List(items)) => {
normalize_accepted_decimal_list_items(inner, items.as_slice()).map(|items| {
items.map_or_else(
|| Cow::Borrowed(value),
|items| Cow::Owned(Value::List(items)),
)
})
}
(
PersistedFieldKind::Map {
key,
value: map_value,
},
Value::Map(entries),
) => normalize_accepted_decimal_map_entries(key, map_value, entries.as_slice()).map(
|entries| {
entries.map_or_else(
|| Cow::Borrowed(value),
|items| Cow::Owned(Value::Map(items)),
)
},
),
_ => Ok(Cow::Borrowed(value)),
}
}
fn decimal_with_accepted_storage_scale(decimal: Decimal, scale: u32) -> Option<Decimal> {
match decimal.scale().cmp(&scale) {
Ordering::Equal => Some(decimal),
Ordering::Less => decimal
.scale_to_integer(scale)
.map(|mantissa| Decimal::from_i128_with_scale(mantissa, scale)),
Ordering::Greater => Some(decimal.round_dp(scale)),
}
}
fn normalize_accepted_decimal_list_items(
kind: &PersistedFieldKind,
items: &[Value],
) -> Result<Option<Vec<Value>>, String> {
let mut normalized = None;
for (index, item) in items.iter().enumerate() {
let value = normalize_decimal_scale_for_accepted_storage(kind, item)?;
if let Cow::Owned(value) = value {
let values = normalized.get_or_insert_with(|| items.to_vec());
values[index] = value;
}
}
Ok(normalized)
}
fn normalize_accepted_decimal_map_entries(
key_kind: &PersistedFieldKind,
value_kind: &PersistedFieldKind,
entries: &[(Value, Value)],
) -> Result<Option<Vec<(Value, Value)>>, String> {
let mut normalized = None;
for (index, (entry_key, entry_value)) in entries.iter().enumerate() {
let key = normalize_decimal_scale_for_accepted_storage(key_kind, entry_key)?;
let value = normalize_decimal_scale_for_accepted_storage(value_kind, entry_value)?;
if matches!(key, Cow::Owned(_)) || matches!(value, Cow::Owned(_)) {
let values = normalized.get_or_insert_with(|| entries.to_vec());
if let Cow::Owned(key) = key {
values[index].0 = key;
}
if let Cow::Owned(value) = value {
values[index].1 = value;
}
}
}
Ok(normalized)
}
fn canonicalize_slot_payload(
model: &'static EntityModel,
slot: usize,
raw_value: &[u8],
) -> Result<Vec<u8>, InternalError> {
let field = generated_compatible_field_model_for_slot(model, slot)?;
let value = decode_runtime_value_from_field_contract(
StructuralFieldDecodeContract::from_field_model(field),
raw_value,
)?;
encode_runtime_value_for_field_model(field, &value)
}
fn dense_slot_image_from_source<F>(
slot_count: usize,
mut encode_slot: F,
) -> Result<Vec<Vec<u8>>, InternalError>
where
F: FnMut(usize) -> Result<Vec<u8>, InternalError>,
{
let mut slot_payloads = Vec::with_capacity(slot_count);
for slot in 0..slot_count {
slot_payloads.push(encode_slot(slot)?);
}
Ok(slot_payloads)
}
fn dense_canonical_slot_image_from_payload_source<'a, F>(
model: &'static EntityModel,
slot_count: usize,
mut payload_for_slot: F,
) -> Result<Vec<Vec<u8>>, InternalError>
where
F: FnMut(usize) -> Result<&'a [u8], InternalError>,
{
dense_slot_image_from_source(slot_count, |slot| {
let payload = payload_for_slot(slot)?;
canonicalize_slot_payload(model, slot, payload)
})
}
fn dense_canonical_slot_image_from_runtime_value_source<'a, F>(
model: &'static EntityModel,
slot_count: usize,
mut value_for_slot: F,
) -> Result<Vec<Vec<u8>>, InternalError>
where
F: FnMut(usize) -> Result<Cow<'a, Value>, InternalError>,
{
dense_slot_image_from_source(slot_count, |slot| {
let field = generated_compatible_field_model_for_slot(model, slot)?;
let value = value_for_slot(slot)?;
encode_runtime_value_for_field_model(field, value.as_ref())
})
}
pub(in crate::db::data::persisted_row) fn encode_slot_payload_from_parts(
slot_count: usize,
slot_table: &[(u32, u32)],
payload_bytes: &[u8],
) -> Result<Vec<u8>, InternalError> {
let field_count = u16::try_from(slot_count).map_err(|_| {
InternalError::persisted_row_encode_failed(format!(
"field count {slot_count} exceeds u16 slot table capacity",
))
})?;
let mut encoded = Vec::with_capacity(
usize::from(field_count) * (u32::BITS as usize / 4) + 2 + payload_bytes.len(),
);
encoded.extend_from_slice(&field_count.to_be_bytes());
for (start, len) in slot_table {
encoded.extend_from_slice(&start.to_be_bytes());
encoded.extend_from_slice(&len.to_be_bytes());
}
encoded.extend_from_slice(payload_bytes);
Ok(encoded)
}
fn encode_slot_payload_from_dense_slot_image<FS, FL>(
slot_payloads: &[Vec<u8>],
mut start_error: FS,
mut len_error: FL,
) -> Result<Vec<u8>, InternalError>
where
FS: FnMut(usize) -> InternalError,
FL: FnMut(usize) -> InternalError,
{
let payload_capacity = slot_payloads
.iter()
.try_fold(0usize, |len, payload| len.checked_add(payload.len()))
.ok_or_else(|| {
InternalError::persisted_row_encode_failed(
"canonical slot image payload length overflow",
)
})?;
let mut payload_bytes = Vec::with_capacity(payload_capacity);
let mut slot_table = Vec::with_capacity(slot_payloads.len());
for (slot, payload) in slot_payloads.iter().enumerate() {
let start = u32::try_from(payload_bytes.len()).map_err(|_| start_error(slot))?;
let len = u32::try_from(payload.len()).map_err(|_| len_error(slot))?;
payload_bytes.extend_from_slice(payload.as_slice());
slot_table.push((start, len));
}
encode_slot_payload_from_parts(slot_payloads.len(), slot_table.as_slice(), &payload_bytes)
}
pub(in crate::db::data::persisted_row) fn canonical_row_from_payload_source<'a, F>(
model: &'static EntityModel,
payload_for_slot: F,
) -> Result<CanonicalRow, InternalError>
where
F: FnMut(usize) -> Result<&'a [u8], InternalError>,
{
let slot_count = model.fields().len();
let slot_payloads =
dense_canonical_slot_image_from_payload_source(model, slot_count, payload_for_slot)?;
emit_raw_row_from_slot_payloads(slot_count, model.path(), slot_payloads.as_slice())
}
pub(in crate::db::data::persisted_row) fn canonical_row_from_runtime_value_source_with_slot_count<
'a,
F,
>(
model: &'static EntityModel,
slot_count: usize,
entity_path: &str,
value_for_slot: F,
) -> Result<CanonicalRow, InternalError>
where
F: FnMut(usize) -> Result<Cow<'a, Value>, InternalError>,
{
let slot_payloads =
dense_canonical_slot_image_from_runtime_value_source(model, slot_count, value_for_slot)?;
emit_raw_row_from_slot_payloads(slot_count, entity_path, slot_payloads.as_slice())
}
fn canonical_row_from_slot_payload_bytes(
row_payload: Vec<u8>,
) -> Result<CanonicalRow, InternalError> {
let encoded = serialize_row_payload(row_payload)?;
let raw_row = RawRow::from_untrusted_bytes(encoded).map_err(InternalError::from)?;
Ok(CanonicalRow::from_canonical_raw_row(raw_row))
}
fn emit_raw_row_from_slot_payloads(
expected_slot_count: usize,
entity_path: &str,
slot_payloads: &[Vec<u8>],
) -> Result<CanonicalRow, InternalError> {
if slot_payloads.len() != expected_slot_count {
return Err(InternalError::persisted_row_encode_failed(format!(
"canonical slot image expected {} slots for entity '{}', found {}",
expected_slot_count,
entity_path,
slot_payloads.len()
)));
}
let row_payload = encode_slot_payload_from_dense_slot_image(
slot_payloads,
|slot| {
InternalError::persisted_row_encode_failed(format!(
"canonical slot payload start exceeds u32 range: slot={slot}",
))
},
|slot| {
InternalError::persisted_row_encode_failed(format!(
"canonical slot payload length exceeds u32 range: slot={slot}",
))
},
)?;
canonical_row_from_slot_payload_bytes(row_payload)
}
fn decode_non_scalar_slot_value(
raw_value: &[u8],
field: StructuralFieldDecodeContract,
) -> Result<Value, InternalError> {
if nullable_non_storage_key_by_kind_slot_payload_is_structural_null(raw_value, field)? {
return Ok(Value::Null);
}
match field.storage_decode() {
crate::model::field::FieldStorageDecode::ByKind => match field.leaf_codec() {
LeafCodec::StructuralFallback if supports_storage_key_binary_kind(field.kind()) => {
match decode_storage_key_binary_value_bytes(raw_value, field.kind()) {
Ok(Some(value)) => Ok(value),
Ok(None) => {
unreachable!("storage-key binary lane must decode supported field kinds")
}
Err(err) => Err(InternalError::persisted_row_field_kind_decode_failed(
field.name(),
field.kind(),
err,
)),
}
}
_ => decode_structural_field_by_kind_bytes(raw_value, field.kind()).map_err(|err| {
InternalError::persisted_row_field_kind_decode_failed(
field.name(),
field.kind(),
err,
)
}),
},
crate::model::field::FieldStorageDecode::Value => {
decode_structural_value_storage_bytes(raw_value).map_err(|err| {
InternalError::persisted_row_field_kind_decode_failed(
field.name(),
field.kind(),
err,
)
})
}
}
}
fn decode_non_scalar_accepted_slot_value(
raw_value: &[u8],
field: AcceptedFieldDecodeContract<'_>,
) -> Result<Value, InternalError> {
if nullable_non_storage_key_accepted_slot_payload_is_structural_null(raw_value, field)? {
return Ok(Value::Null);
}
match field.storage_decode() {
FieldStorageDecode::ByKind => {
decode_structural_field_by_accepted_kind_bytes(raw_value, field.kind()).map_err(|err| {
InternalError::persisted_row_field_kind_decode_failed(
field.field_name(),
field.kind(),
err,
)
})
}
FieldStorageDecode::Value => {
decode_structural_value_storage_bytes(raw_value).map_err(|err| {
InternalError::persisted_row_field_kind_decode_failed(
field.field_name(),
field.kind(),
err,
)
})
}
}
}
pub(in crate::db::data::persisted_row) fn validate_non_scalar_slot_value(
raw_value: &[u8],
field: StructuralFieldDecodeContract,
) -> Result<(), InternalError> {
if nullable_non_storage_key_by_kind_slot_payload_is_structural_null(raw_value, field)? {
return Ok(());
}
match field.storage_decode() {
crate::model::field::FieldStorageDecode::ByKind => match field.leaf_codec() {
LeafCodec::StructuralFallback if supports_storage_key_binary_kind(field.kind()) => {
match validate_storage_key_binary_value_bytes(raw_value, field.kind()) {
Ok(true) => Ok(()),
Ok(false) => {
unreachable!("storage-key binary lane must validate supported field kinds")
}
Err(err) => Err(InternalError::persisted_row_field_kind_decode_failed(
field.name(),
field.kind(),
err,
)),
}
}
_ => validate_structural_field_by_kind_bytes(raw_value, field.kind()).map_err(|err| {
InternalError::persisted_row_field_kind_decode_failed(
field.name(),
field.kind(),
err,
)
}),
},
crate::model::field::FieldStorageDecode::Value => {
validate_structural_value_storage_bytes(raw_value).map_err(|err| {
InternalError::persisted_row_field_kind_decode_failed(
field.name(),
field.kind(),
err,
)
})
}
}
}
pub(in crate::db) fn validate_non_scalar_accepted_slot_value(
raw_value: &[u8],
field: AcceptedFieldDecodeContract<'_>,
) -> Result<(), InternalError> {
if nullable_non_storage_key_accepted_slot_payload_is_structural_null(raw_value, field)? {
return Ok(());
}
match field.storage_decode() {
FieldStorageDecode::ByKind => {
validate_structural_field_by_accepted_kind_bytes(raw_value, field.kind()).map_err(
|err| {
InternalError::persisted_row_field_kind_decode_failed(
field.field_name(),
field.kind(),
err,
)
},
)
}
FieldStorageDecode::Value => {
validate_structural_value_storage_bytes(raw_value).map_err(|err| {
InternalError::persisted_row_field_kind_decode_failed(
field.field_name(),
field.kind(),
err,
)
})
}
}
}
pub(in crate::db) fn validate_non_scalar_slot_value_with_row_contract(
contract: &StructuralRowContract,
slot: usize,
raw_value: &[u8],
) -> Result<(), InternalError> {
if let Some(accepted_field) = contract.accepted_field_decode_contract(slot) {
return validate_non_scalar_accepted_slot_value(raw_value, accepted_field);
}
let field = contract.field_decode_contract(slot)?;
validate_non_scalar_slot_value(raw_value, field)
}
fn nullable_non_storage_key_by_kind_slot_payload_is_structural_null(
raw_value: &[u8],
field: StructuralFieldDecodeContract,
) -> Result<bool, InternalError> {
if !field.nullable()
|| !matches!(field.storage_decode(), FieldStorageDecode::ByKind)
|| supports_storage_key_binary_kind(field.kind())
{
return Ok(false);
}
value_storage_bytes_are_null(raw_value).map_err(|err| {
InternalError::persisted_row_field_kind_decode_failed(field.name(), field.kind(), err)
})
}
fn nullable_non_storage_key_accepted_slot_payload_is_structural_null(
raw_value: &[u8],
field: AcceptedFieldDecodeContract<'_>,
) -> Result<bool, InternalError> {
if !field.nullable()
|| !matches!(field.storage_decode(), FieldStorageDecode::ByKind)
|| accepted_kind_supports_storage_key_binary(field.kind())
{
return Ok(false);
}
value_storage_bytes_are_null(raw_value).map_err(|err| {
InternalError::persisted_row_field_kind_decode_failed(field.field_name(), field.kind(), err)
})
}