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}