1use crate::{OperationControl, OperationControlResult};
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3#[cfg(any(
4 test,
5 feature = "diagram-mindmap",
6 feature = "diagram-state",
7 feature = "diagram-usecase"
8))]
9use serde_json::Number;
10use serde_json::{Map, Value};
11use std::collections::HashMap;
12use std::fmt;
13use std::io::Write;
14use std::mem::size_of;
15use std::ops::Deref;
16
17#[derive(Default)]
24pub struct ManagedSemanticJson {
25 value: Value,
26}
27
28impl ManagedSemanticJson {
29 pub fn from_value(value: Value) -> Self {
31 Self { value }
32 }
33
34 pub fn as_value(&self) -> &Value {
36 &self.value
37 }
38
39 pub(crate) fn as_value_mut(&mut self) -> &mut Value {
40 &mut self.value
41 }
42
43 pub fn into_unmanaged_value(mut self) -> Value {
47 std::mem::take(&mut self.value)
48 }
49
50 pub fn clone_controlled(&self, control: &OperationControl) -> OperationControlResult<Self> {
52 clone_value_nonrecursive_with_control(&self.value, control).map(Self::from_value)
53 }
54
55 pub fn write_json(&self, writer: impl Write) -> serde_json::Result<()> {
57 self.write_json_controlled(writer, &OperationControl::new())
58 .expect("a private operation control cannot be cancelled")
59 }
60
61 pub fn write_json_controlled(
67 &self,
68 writer: impl Write,
69 control: &OperationControl,
70 ) -> OperationControlResult<serde_json::Result<()>> {
71 self.write_with_formatter(writer, control, serde_json::ser::CompactFormatter)
72 }
73
74 pub fn write_json_pretty(&self, writer: impl Write) -> serde_json::Result<()> {
76 self.write_json_pretty_controlled(writer, &OperationControl::new())
77 .expect("a private operation control cannot be cancelled")
78 }
79
80 pub fn write_json_pretty_controlled(
82 &self,
83 writer: impl Write,
84 control: &OperationControl,
85 ) -> OperationControlResult<serde_json::Result<()>> {
86 self.write_with_formatter(writer, control, serde_json::ser::PrettyFormatter::new())
87 }
88
89 fn write_with_formatter(
90 &self,
91 mut writer: impl Write,
92 control: &OperationControl,
93 mut formatter: impl serde_json::ser::Formatter,
94 ) -> OperationControlResult<serde_json::Result<()>> {
95 enum Task<'a> {
96 Value(&'a Value),
97 Key(&'a str),
98 ArrayItems(std::slice::Iter<'a, Value>, bool),
99 ObjectEntries(serde_json::map::Iter<'a>, bool),
100 ArrayValue(bool),
101 ArrayValueEnd,
102 ArrayEnd,
103 ObjectKey(bool),
104 ObjectValue,
105 ObjectValueEnd,
106 ObjectEnd,
107 }
108
109 let mut stack = vec![Task::Value(&self.value)];
110 let mut steps = 0usize;
111 while let Some(task) = stack.pop() {
112 if steps.is_multiple_of(64) {
113 control.checkpoint()?;
114 }
115 steps = steps.saturating_add(1);
116 let result = match task {
117 Task::ArrayItems(mut items, first) => {
118 if let Some(item) = items.next() {
119 stack.push(Task::ArrayItems(items, false));
120 stack.push(Task::ArrayValueEnd);
121 stack.push(Task::Value(item));
122 stack.push(Task::ArrayValue(first));
123 }
124 Ok(())
125 }
126 Task::ObjectEntries(mut entries, first) => {
127 if let Some((key, value)) = entries.next() {
128 stack.push(Task::ObjectEntries(entries, false));
129 stack.push(Task::ObjectValueEnd);
130 stack.push(Task::Value(value));
131 stack.push(Task::ObjectValue);
132 stack.push(Task::Key(key));
133 stack.push(Task::ObjectKey(first));
134 }
135 Ok(())
136 }
137 Task::ArrayValue(first) => formatter
138 .begin_array_value(&mut writer, first)
139 .map_err(serde_json::Error::io),
140 Task::ArrayValueEnd => formatter
141 .end_array_value(&mut writer)
142 .map_err(serde_json::Error::io),
143 Task::ArrayEnd => formatter
144 .end_array(&mut writer)
145 .map_err(serde_json::Error::io),
146 Task::ObjectKey(first) => formatter
147 .begin_object_key(&mut writer, first)
148 .map_err(serde_json::Error::io),
149 Task::ObjectValue => formatter
150 .begin_object_value(&mut writer)
151 .map_err(serde_json::Error::io),
152 Task::ObjectValueEnd => formatter
153 .end_object_value(&mut writer)
154 .map_err(serde_json::Error::io),
155 Task::ObjectEnd => formatter
156 .end_object(&mut writer)
157 .map_err(serde_json::Error::io),
158 Task::Key(key) => serde_json::to_writer(&mut writer, key),
159 Task::Value(Value::Array(items)) => {
160 stack.push(Task::ArrayEnd);
161 stack.push(Task::ArrayItems(items.iter(), true));
162 formatter
163 .begin_array(&mut writer)
164 .map_err(serde_json::Error::io)
165 }
166 Task::Value(Value::Object(entries)) => {
167 stack.push(Task::ObjectEnd);
168 stack.push(Task::ObjectEntries(entries.iter(), true));
169 formatter
170 .begin_object(&mut writer)
171 .map_err(serde_json::Error::io)
172 }
173 Task::Value(scalar) => serde_json::to_writer(&mut writer, scalar),
174 };
175 if let Err(error) = result {
176 if let Some(cancelled) = control.observed_cancellation() {
177 return Err(cancelled);
178 }
179 return Ok(Err(error));
180 }
181 }
182 control.checkpoint()?;
183 Ok(Ok(()))
184 }
185}
186
187impl From<Value> for ManagedSemanticJson {
188 fn from(value: Value) -> Self {
189 Self::from_value(value)
190 }
191}
192
193impl From<&Value> for ManagedSemanticJson {
194 fn from(value: &Value) -> Self {
195 Self::from_value(clone_value_nonrecursive(value))
196 }
197}
198
199impl Deref for ManagedSemanticJson {
200 type Target = Value;
201
202 fn deref(&self) -> &Self::Target {
203 self.as_value()
204 }
205}
206
207impl AsRef<Value> for ManagedSemanticJson {
208 fn as_ref(&self) -> &Value {
209 self.as_value()
210 }
211}
212
213impl Clone for ManagedSemanticJson {
214 fn clone(&self) -> Self {
215 Self::from(&self.value)
216 }
217}
218
219impl Drop for ManagedSemanticJson {
220 fn drop(&mut self) {
221 drop_value_nonrecursive(std::mem::take(&mut self.value));
222 }
223}
224
225pub(crate) fn equal_values(left: &Value, right: &Value) -> bool {
226 let mut stack = vec![(left, right)];
227 while let Some((left, right)) = stack.pop() {
228 match (left, right) {
229 (Value::Array(left), Value::Array(right)) if left.len() == right.len() => {
230 stack.extend(left.iter().zip(right));
231 }
232 (Value::Object(left), Value::Object(right)) if left.len() == right.len() => {
233 for (key, value) in left {
234 let Some(other) = right.get(key) else {
235 return false;
236 };
237 stack.push((value, other));
238 }
239 }
240 (Value::Null, Value::Null) => {}
241 (Value::Bool(left), Value::Bool(right)) if left == right => {}
242 (Value::Number(left), Value::Number(right)) if left == right => {}
243 (Value::String(left), Value::String(right)) if left == right => {}
244 _ => return false,
245 }
246 }
247 true
248}
249
250impl PartialEq for ManagedSemanticJson {
251 fn eq(&self, other: &Self) -> bool {
252 equal_values(&self.value, &other.value)
253 }
254}
255
256impl Eq for ManagedSemanticJson {}
257
258impl PartialEq<Value> for ManagedSemanticJson {
259 fn eq(&self, other: &Value) -> bool {
260 equal_values(&self.value, other)
261 }
262}
263
264impl PartialEq<ManagedSemanticJson> for Value {
265 fn eq(&self, other: &ManagedSemanticJson) -> bool {
266 equal_values(self, &other.value)
267 }
268}
269
270impl fmt::Debug for ManagedSemanticJson {
271 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
272 let mut bytes = Vec::new();
273 self.write_json(&mut bytes).map_err(|_| fmt::Error)?;
274 formatter.write_str(std::str::from_utf8(&bytes).map_err(|_| fmt::Error)?)
275 }
276}
277
278impl Serialize for ManagedSemanticJson {
279 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
280 let mut stack = vec![(&self.value, 0usize)];
281 while let Some((value, depth)) = stack.pop() {
282 if !matches!(value, Value::Array(_) | Value::Object(_)) {
283 continue;
284 }
285 let container_depth = depth.saturating_add(1);
286 if container_depth > 128 {
287 return Err(serde::ser::Error::custom(
288 "semantic JSON exceeds generic serde's 128-container depth; use write_json",
289 ));
290 }
291 match value {
292 Value::Array(items) => {
293 stack.extend(
294 items
295 .iter()
296 .filter(|child| matches!(child, Value::Array(_) | Value::Object(_)))
297 .map(|child| (child, container_depth)),
298 );
299 }
300 Value::Object(entries) => {
301 stack.extend(
302 entries
303 .values()
304 .filter(|child| matches!(child, Value::Array(_) | Value::Object(_)))
305 .map(|child| (child, container_depth)),
306 );
307 }
308 _ => unreachable!("container kind was checked above"),
309 }
310 }
311 self.value.serialize(serializer)
312 }
313}
314
315impl<'de> Deserialize<'de> for ManagedSemanticJson {
316 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
317 Value::deserialize(deserializer).map(Self::from_value)
318 }
319}
320
321#[cfg(any(
322 test,
323 feature = "diagram-mindmap",
324 feature = "diagram-state",
325 feature = "diagram-usecase"
326))]
327pub(crate) fn number_value(value: f64) -> Value {
328 if value.is_finite()
329 && value.fract() == 0.0
330 && value >= i64::MIN as f64
331 && value < i64::MAX as f64
332 {
333 Value::Number(Number::from(value as i64))
334 } else {
335 Number::from_f64(value)
336 .map(Value::Number)
337 .unwrap_or(Value::Null)
338 }
339}
340
341pub(crate) fn clone_value_nonrecursive(value: &Value) -> Value {
342 let control = OperationControl::new();
343 clone_value_nonrecursive_with_control(value, &control)
344 .expect("a private operation control cannot be cancelled")
345}
346
347pub(crate) fn clone_value_nonrecursive_with_control(
348 value: &Value,
349 control: &OperationControl,
350) -> OperationControlResult<Value> {
351 clone_value_nonrecursive_controlled(value, usize::MAX, usize::MAX, control)
352 .map(|value| value.expect("unbounded config cloning cannot exceed its budget"))
353}
354
355pub(crate) fn clone_value_nonrecursive_controlled(
356 value: &Value,
357 max_retained_bytes: usize,
358 max_nesting_depth: usize,
359 control: &OperationControl,
360) -> OperationControlResult<Option<Value>> {
361 let mut cloned: HashMap<*const Value, Value> = HashMap::new();
362 let mut stack = vec![(value, false, 0usize)];
363 let mut retained_bytes = 0usize;
364 let mut visited_nodes = 0usize;
365
366 while let Some((current, visited, depth)) = stack.pop() {
367 if visited_nodes.is_multiple_of(64)
368 && let Err(cancelled) = control.checkpoint()
369 {
370 drop_cloned_values(cloned);
371 return Err(cancelled);
372 }
373 visited_nodes = visited_nodes.saturating_add(1);
374 let current_ptr = std::ptr::from_ref(current);
375 if visited {
376 retained_bytes = retained_bytes.saturating_add(value_clone_weight(current));
377 if retained_bytes > max_retained_bytes {
378 drop_cloned_values(cloned);
379 return Ok(None);
380 }
381 let value = match current {
382 Value::Null => Value::Null,
383 Value::Bool(v) => Value::Bool(*v),
384 Value::Number(v) => Value::Number(v.clone()),
385 Value::String(v) => Value::String(v.clone()),
386 Value::Array(items) => {
387 let mut out = Vec::with_capacity(items.len());
388 for (index, item) in items.iter().enumerate() {
389 if index.is_multiple_of(64)
390 && let Err(cancelled) = control.checkpoint()
391 {
392 drop_value_nonrecursive(Value::Array(out));
393 drop_cloned_values(cloned);
394 return Err(cancelled);
395 }
396 if let Some(value) = cloned.remove(&std::ptr::from_ref(item)) {
397 out.push(value);
398 }
399 }
400 Value::Array(out)
401 }
402 Value::Object(entries) => {
403 let mut out = Map::new();
404 for (index, (key, child)) in entries.iter().enumerate() {
405 if index.is_multiple_of(64)
406 && let Err(cancelled) = control.checkpoint()
407 {
408 drop_value_nonrecursive(Value::Object(out));
409 drop_cloned_values(cloned);
410 return Err(cancelled);
411 }
412 if let Some(value) = cloned.remove(&std::ptr::from_ref(child)) {
413 out.insert(key.clone(), value);
414 }
415 }
416 Value::Object(out)
417 }
418 };
419 cloned.insert(current_ptr, value);
420 } else {
421 let has_children = matches!(current, Value::Array(items) if !items.is_empty())
422 || matches!(current, Value::Object(entries) if !entries.is_empty());
423 if has_children && depth >= max_nesting_depth {
424 drop_cloned_values(cloned);
425 return Ok(None);
426 }
427 let structural_weight = value_structural_weight(current);
428 retained_bytes = retained_bytes.saturating_add(structural_weight);
429 if retained_bytes > max_retained_bytes {
430 drop_cloned_values(cloned);
431 return Ok(None);
432 }
433 stack.push((current, true, depth));
434 match current {
435 Value::Array(items) => {
436 for item in items.iter().rev() {
437 stack.push((item, false, depth.saturating_add(1)));
438 }
439 }
440 Value::Object(entries) => {
441 for child in entries.values().rev() {
442 stack.push((child, false, depth.saturating_add(1)));
443 }
444 }
445 Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => {}
446 }
447 }
448 }
449
450 if let Err(cancelled) = control.checkpoint() {
451 drop_cloned_values(cloned);
452 return Err(cancelled);
453 }
454 Ok(Some(
455 cloned
456 .remove(&std::ptr::from_ref(value))
457 .unwrap_or(Value::Null),
458 ))
459}
460
461fn value_structural_weight(value: &Value) -> usize {
462 match value {
463 Value::Array(items) => items.len().saturating_mul(size_of::<Value>()),
464 Value::Object(entries) => entries.iter().fold(
465 entries.len().saturating_mul(
466 size_of::<String>()
467 .saturating_add(size_of::<Value>())
468 .saturating_add(size_of::<usize>().saturating_mul(4)),
469 ),
470 |weight, (key, _)| weight.saturating_add(key.len()),
471 ),
472 Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => 0,
473 }
474}
475
476fn value_clone_weight(value: &Value) -> usize {
477 size_of::<Value>().saturating_add(match value {
478 Value::String(value) => value.len(),
479 Value::Null | Value::Bool(_) | Value::Number(_) | Value::Array(_) | Value::Object(_) => 0,
480 })
481}
482
483#[cfg(test)]
484pub(crate) fn estimated_value_owned_heap_bytes(value: &Value) -> usize {
485 let mut retained_bytes = 0usize;
486 let mut stack = vec![value];
487 while let Some(current) = stack.pop() {
488 retained_bytes = retained_bytes
489 .saturating_add(value_structural_weight(current))
490 .saturating_add(value_clone_weight(current));
491 match current {
492 Value::Array(items) => stack.extend(items),
493 Value::Object(entries) => stack.extend(entries.values()),
494 Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => {}
495 }
496 }
497 retained_bytes
498}
499
500fn drop_cloned_values(cloned: HashMap<*const Value, Value>) {
501 for value in cloned.into_values() {
502 drop_value_nonrecursive(value);
503 }
504}
505
506pub(crate) fn drop_value_nonrecursive(value: Value) {
507 let mut stack = vec![value];
508 while let Some(value) = stack.pop() {
509 match value {
510 Value::Array(items) => {
511 stack.extend(items);
512 }
513 Value::Object(entries) => {
514 stack.extend(entries.into_values());
515 }
516 Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => {}
517 }
518 }
519}
520
521#[cfg(test)]
522mod tests {
523 use super::*;
524
525 #[test]
526 fn number_projection_does_not_saturate_at_the_rounded_i64_upper_bound() {
527 let upper_bound = i64::MAX as f64;
528 let projected = number_value(upper_bound);
529 assert_eq!(projected.as_f64(), Some(upper_bound));
530 assert_ne!(projected, Value::Number(Number::from(i64::MAX)));
531 assert_eq!(
532 number_value(i64::MIN as f64),
533 Value::Number(Number::from(i64::MIN))
534 );
535 assert_eq!(number_value(-0.0), Value::Number(Number::from(0)));
536 assert_eq!(number_value(f64::INFINITY), Value::Null);
537 }
538}