Skip to main content

qubit_metadata/
metadata_limits_builder.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Builder for [`crate::MetadataLimits`].
9
10use qubit_budget::json::JsonDecodeLimits;
11use qubit_budget::json::JsonEncodeLimits;
12
13use crate::metadata_limits::DEFAULT_MAX_KEY_BYTES;
14use crate::metadata_limits::DEFAULT_MAX_METADATA_ENTRIES;
15use crate::metadata_limits::DEFAULT_MAX_SCHEMA_FIELDS;
16use crate::metadata_limits::MetadataLimits;
17use crate::metadata_limits::default_json_decode_limits;
18use crate::metadata_limits::default_json_encode_limits;
19
20/// Builder for [`MetadataLimits`].
21///
22/// # Examples
23///
24/// ```
25/// use qubit_metadata::MetadataLimits;
26///
27/// # fn main() -> Result<(), serde_json::Error> {
28/// let limits = MetadataLimits::builder().max_metadata_entries(128).build()?;
29/// assert_eq!(limits.max_metadata_entries(), 128);
30/// # Ok(())
31/// # }
32/// ```
33#[must_use]
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35pub struct MetadataLimitsBuilder {
36    /// Receiver-controlled JSON budgets applied while decoding untrusted input.
37    pub(crate) json_decode: JsonDecodeLimits,
38    /// Preflight and output budgets applied while encoding metadata documents.
39    pub(crate) json_encode: JsonEncodeLimits,
40    /// Cardinality ceiling shared by metadata wire-map operations.
41    pub(crate) max_metadata_entries: usize,
42    /// Cardinality ceiling shared by schema wire-map operations.
43    pub(crate) max_schema_fields: usize,
44    /// UTF-8 byte ceiling shared by metadata and schema keys.
45    pub(crate) max_key_bytes: usize,
46}
47
48impl MetadataLimitsBuilder {
49    /// Replaces the JSON decoding profile.
50    ///
51    /// # Parameters
52    ///
53    /// * `limits` - JSON decoding budgets to apply.
54    ///
55    /// # Returns
56    ///
57    /// The updated builder.
58    #[inline(always)]
59    pub fn json_decode(mut self, limits: JsonDecodeLimits) -> Self {
60        self.json_decode = limits;
61        self
62    }
63
64    /// Replaces the JSON encoding profile.
65    ///
66    /// # Parameters
67    ///
68    /// * `limits` - JSON encoding budgets to apply.
69    ///
70    /// # Returns
71    ///
72    /// The updated builder.
73    #[inline(always)]
74    pub fn json_encode(mut self, limits: JsonEncodeLimits) -> Self {
75        self.json_encode = limits;
76        self
77    }
78
79    /// Sets the metadata-entry domain limit.
80    ///
81    /// # Parameters
82    ///
83    /// * `maximum` - Maximum number of metadata entries.
84    ///
85    /// # Returns
86    ///
87    /// The updated builder.
88    #[inline(always)]
89    pub const fn max_metadata_entries(mut self, maximum: usize) -> Self {
90        self.max_metadata_entries = maximum;
91        self
92    }
93
94    /// Sets the schema-field domain limit.
95    ///
96    /// # Parameters
97    ///
98    /// * `maximum` - Maximum number of schema fields.
99    ///
100    /// # Returns
101    ///
102    /// The updated builder.
103    #[inline(always)]
104    pub const fn max_schema_fields(mut self, maximum: usize) -> Self {
105        self.max_schema_fields = maximum;
106        self
107    }
108
109    /// Sets the metadata/schema key-byte domain limit.
110    ///
111    /// # Parameters
112    ///
113    /// * `maximum` - Maximum UTF-8 byte length of a key.
114    ///
115    /// # Returns
116    ///
117    /// The updated builder.
118    #[inline(always)]
119    pub const fn max_key_bytes(mut self, maximum: usize) -> Self {
120        self.max_key_bytes = maximum;
121        self
122    }
123
124    /// Builds validated metadata limits by consuming this builder.
125    ///
126    /// # Errors
127    ///
128    /// Returns a configuration error when a domain limit exceeds its protocol
129    /// hard cap. Validation happens while building the limits.
130    #[inline]
131    pub fn build(self) -> Result<MetadataLimits, serde_json::Error> {
132        let limits = MetadataLimits::from_builder(self);
133        limits.validate()?;
134        Ok(limits)
135    }
136}
137
138impl Default for MetadataLimitsBuilder {
139    /// Creates a builder with default JSON budgets and domain limits.
140    fn default() -> Self {
141        Self {
142            json_decode: default_json_decode_limits(),
143            json_encode: default_json_encode_limits(),
144            max_metadata_entries: DEFAULT_MAX_METADATA_ENTRIES,
145            max_schema_fields: DEFAULT_MAX_SCHEMA_FIELDS,
146            max_key_bytes: DEFAULT_MAX_KEY_BYTES,
147        }
148    }
149}