use qubit_budget::ResourceLimit;
use qubit_budget::json::JsonDecodeLimits;
use qubit_budget::json::JsonEncodeLimits;
use qubit_budget::json::JsonResource;
use qubit_budget::json::JsonValueLimits;
use serde::de::Error as _;
use crate::metadata_limits_builder::MetadataLimitsBuilder;
pub const DEFAULT_MAX_JSON_BYTES: usize = 1_048_576;
pub const DEFAULT_MAX_METADATA_ENTRIES: usize = 4_096;
pub const DEFAULT_MAX_SCHEMA_FIELDS: usize = 4_096;
pub const DEFAULT_MAX_KEY_BYTES: usize = 256;
#[must_use]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MetadataLimits {
json_decode: JsonDecodeLimits,
json_encode: JsonEncodeLimits,
max_metadata_entries: usize,
max_schema_fields: usize,
max_key_bytes: usize,
}
impl MetadataLimits {
#[inline(always)]
#[must_use = "the builder must be configured or used to build metadata limits"]
pub fn builder() -> MetadataLimitsBuilder {
MetadataLimitsBuilder::default()
}
#[cfg(debug_assertions)]
#[doc(hidden)]
pub fn debug_only_invalid_domain_limits(
max_metadata_entries: usize,
max_schema_fields: usize,
max_key_bytes: usize,
) -> Self {
MetadataLimits::from_builder(
MetadataLimitsBuilder::default()
.max_metadata_entries(max_metadata_entries)
.max_schema_fields(max_schema_fields)
.max_key_bytes(max_key_bytes),
)
}
#[inline]
pub(crate) fn from_builder(builder: MetadataLimitsBuilder) -> Self {
Self {
json_decode: builder.json_decode,
json_encode: builder.json_encode,
max_metadata_entries: builder.max_metadata_entries,
max_schema_fields: builder.max_schema_fields,
max_key_bytes: builder.max_key_bytes,
}
}
#[inline(always)]
#[must_use]
pub const fn json_decode(&self) -> JsonDecodeLimits {
self.json_decode
}
#[inline(always)]
#[must_use]
pub const fn json_encode(&self) -> JsonEncodeLimits {
self.json_encode
}
#[inline(always)]
#[must_use]
pub const fn max_metadata_entries(&self) -> usize {
self.max_metadata_entries
}
#[inline(always)]
#[must_use]
pub const fn max_schema_fields(&self) -> usize {
self.max_schema_fields
}
#[inline(always)]
#[must_use]
pub const fn max_key_bytes(&self) -> usize {
self.max_key_bytes
}
pub fn validate(&self) -> Result<(), serde_json::Error> {
if self.max_metadata_entries > DEFAULT_MAX_METADATA_ENTRIES {
return Err(serde_json::Error::custom(format!(
"metadata entries limit {} exceeds {}",
self.max_metadata_entries, DEFAULT_MAX_METADATA_ENTRIES,
)));
}
if self.max_schema_fields > DEFAULT_MAX_SCHEMA_FIELDS {
return Err(serde_json::Error::custom(format!(
"schema fields limit {} exceeds {}",
self.max_schema_fields, DEFAULT_MAX_SCHEMA_FIELDS,
)));
}
if self.max_key_bytes > DEFAULT_MAX_KEY_BYTES {
return Err(serde_json::Error::custom(format!(
"metadata key limit {} exceeds {}",
self.max_key_bytes, DEFAULT_MAX_KEY_BYTES,
)));
}
Ok(())
}
}
impl Default for MetadataLimits {
fn default() -> Self {
Self::builder()
.build()
.expect("default metadata limits satisfy protocol hard caps")
}
}
pub fn default_json_value_limits() -> JsonValueLimits {
JsonValueLimits::<JsonResource, usize>::builder()
.max_depth(64_usize)
.max_nodes(100_000_usize)
.max_sequence_items(4_096_usize)
.max_map_entries(json_quantity(DEFAULT_MAX_METADATA_ENTRIES))
.max_key_bytes(256 * 1024_usize)
.max_string_bytes(256 * 1024_usize)
.max_number_bytes(4_096_usize)
.max_payload_bytes(json_quantity(DEFAULT_MAX_JSON_BYTES))
.build()
}
pub fn default_json_decode_limits() -> JsonDecodeLimits {
JsonDecodeLimits::builder()
.input_bytes_limit(ResourceLimit::new(
JsonResource::InputBytes,
json_quantity(DEFAULT_MAX_JSON_BYTES),
))
.value_limits(default_json_value_limits())
.build()
}
pub fn default_json_encode_limits() -> JsonEncodeLimits {
JsonEncodeLimits::builder()
.output_bytes_limit(ResourceLimit::new(
JsonResource::OutputBytes,
json_quantity(DEFAULT_MAX_JSON_BYTES),
))
.value_limits(default_json_value_limits())
.build()
}
fn json_quantity(value: usize) -> usize {
value
}