1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// =============================================================================
// Copyright (c) 2025 - 2026 Haixing Hu.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0.
// =============================================================================
//! Defines the policy used by the normalizing JSON decoder.
use super::DiagnosticPolicy;
use super::MarkdownFenceClosing;
use super::MarkdownFencePolicy;
use super::NormalizingJsonDecodePolicyBuilder;
/// Text-normalization and diagnostic policy for
/// [`crate::decode::NormalizingJsonDecoder`].
///
/// Resource limits deliberately live in
/// [`qubit_budget::json::JsonDecodeLimits`]
/// and are supplied separately when constructing a decoder.
///
/// # Examples
///
/// ```
/// use qubit_json::decode::NormalizingJsonDecodePolicy;
///
/// let policy = NormalizingJsonDecodePolicy::builder()
/// .trim_whitespace(false)
/// .build();
/// assert!(!policy.trim_whitespace());
/// ```
#[must_use]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NormalizingJsonDecodePolicy {
/// Whether leading and trailing whitespace is removed.
trim_whitespace: bool,
/// Whether a leading UTF-8 byte order mark is removed.
strip_utf8_bom: bool,
/// How one outer Markdown code fence is handled.
markdown_fence_policy: MarkdownFencePolicy,
/// Whether raw ASCII control characters in strings are escaped.
escape_control_chars_in_strings: bool,
/// Whether input-derived decoding details are retained.
diagnostic_policy: DiagnosticPolicy,
}
impl NormalizingJsonDecodePolicy {
/// Creates the default permissive normalization policy.
///
/// The defaults trim surrounding whitespace, strip a leading UTF-8 BOM,
/// accept JSON-only Markdown fences with an optional closing fence, escape
/// raw string control characters, and redact input-derived diagnostics.
///
/// # Returns
///
/// A policy with the documented permissive defaults.
#[inline]
pub const fn lenient() -> Self {
Self {
trim_whitespace: true,
strip_utf8_bom: true,
markdown_fence_policy: MarkdownFencePolicy::JsonOnly {
closing: MarkdownFenceClosing::Optional,
},
escape_control_chars_in_strings: true,
diagnostic_policy: DiagnosticPolicy::Redacted,
}
}
/// Creates a builder initialized with the lenient policy.
///
/// # Returns
///
/// A builder whose fields can be selectively changed before `build`.
#[inline]
#[must_use]
pub const fn builder() -> NormalizingJsonDecodePolicyBuilder {
NormalizingJsonDecodePolicyBuilder::new()
}
/// Returns whether surrounding whitespace is removed.
///
/// # Returns
///
/// `true` when leading and trailing whitespace is discarded before JSON
/// parsing.
#[inline(always)]
#[must_use]
pub const fn trim_whitespace(&self) -> bool {
self.trim_whitespace
}
/// Returns whether a leading UTF-8 byte order mark is removed.
///
/// # Returns
///
/// `true` when a leading UTF-8 BOM is discarded before JSON parsing.
#[inline(always)]
#[must_use]
pub const fn strip_utf8_bom(&self) -> bool {
self.strip_utf8_bom
}
/// Returns the outer Markdown fence policy.
///
/// # Returns
///
/// A shared reference to the policy governing Markdown fence stripping.
#[inline(always)]
#[must_use]
pub const fn markdown_fence_policy(&self) -> &MarkdownFencePolicy {
&self.markdown_fence_policy
}
/// Returns whether raw control characters in strings are escaped.
///
/// # Returns
///
/// `true` when raw JSON string control characters are rewritten to escaped
/// forms during normalization.
#[inline(always)]
#[must_use]
pub const fn escape_control_chars_in_strings(&self) -> bool {
self.escape_control_chars_in_strings
}
/// Returns the error diagnostic policy.
///
/// # Returns
///
/// The policy controlling retention of input-derived error details.
#[inline(always)]
#[must_use]
pub const fn diagnostic_policy(&self) -> DiagnosticPolicy {
self.diagnostic_policy
}
/// Updates whitespace trimming during builder composition.
#[inline(always)]
pub(super) const fn set_trim_whitespace(&mut self, enabled: bool) {
self.trim_whitespace = enabled;
}
/// Updates BOM stripping during builder composition.
#[inline(always)]
pub(super) const fn set_strip_utf8_bom(&mut self, enabled: bool) {
self.strip_utf8_bom = enabled;
}
/// Updates Markdown fence handling during builder composition.
#[inline(always)]
pub(super) const fn set_markdown_fence_policy(&mut self, policy: MarkdownFencePolicy) {
self.markdown_fence_policy = policy;
}
/// Updates control-character escaping during builder composition.
#[inline(always)]
pub(super) const fn set_escape_control_chars_in_strings(&mut self, enabled: bool) {
self.escape_control_chars_in_strings = enabled;
}
/// Updates diagnostic handling during builder composition.
#[inline(always)]
pub(super) const fn set_diagnostic_policy(&mut self, policy: DiagnosticPolicy) {
self.diagnostic_policy = policy;
}
}
impl Default for NormalizingJsonDecodePolicy {
/// Creates the default lenient policy.
#[inline(always)]
fn default() -> Self {
Self::lenient()
}
}