1use indexmap::IndexMap;
13use serde::{Deserialize, Deserializer, Serialize, Serializer};
14use serde_json::Value as JsonValue;
15use std::ops::Deref;
16use std::sync::OnceLock;
17
18pub struct QuillValue {
27 node: Node,
28 json: OnceLock<JsonValue>,
30}
31
32#[derive(Debug, Clone, PartialEq)]
34struct Node {
35 fill: bool,
36 kind: Kind,
37}
38
39#[derive(Debug, Clone, PartialEq)]
40enum Kind {
41 Null,
42 Bool(bool),
43 Number(serde_json::Number),
44 String(String),
45 Array(Vec<Node>),
46 Object(IndexMap<String, Node>),
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Hash)]
54pub enum PathSegment {
55 Key(String),
56 Index(usize),
57}
58
59fn collect_fill_paths(node: &Node, prefix: &mut Vec<PathSegment>, out: &mut Vec<Vec<PathSegment>>) {
60 if node.fill {
61 out.push(prefix.clone());
62 }
63 match &node.kind {
64 Kind::Array(items) => {
65 for (i, child) in items.iter().enumerate() {
66 prefix.push(PathSegment::Index(i));
67 collect_fill_paths(child, prefix, out);
68 prefix.pop();
69 }
70 }
71 Kind::Object(entries) => {
72 for (k, child) in entries {
73 prefix.push(PathSegment::Key(k.clone()));
74 collect_fill_paths(child, prefix, out);
75 prefix.pop();
76 }
77 }
78 _ => {}
79 }
80}
81
82fn node_at_mut<'a>(node: &'a mut Node, path: &[PathSegment]) -> Option<&'a mut Node> {
83 let mut cur = node;
84 for seg in path {
85 cur = match (&mut cur.kind, seg) {
86 (Kind::Object(entries), PathSegment::Key(k)) => entries.get_mut(k)?,
87 (Kind::Array(items), PathSegment::Index(i)) => items.get_mut(*i)?,
88 _ => return None,
89 };
90 }
91 Some(cur)
92}
93
94fn node_is_object(node: &Node, path: &[PathSegment]) -> bool {
95 fn at<'a>(node: &'a Node, path: &[PathSegment]) -> Option<&'a Node> {
96 let mut cur = node;
97 for seg in path {
98 cur = match (&cur.kind, seg) {
99 (Kind::Object(entries), PathSegment::Key(k)) => entries.get(k)?,
100 (Kind::Array(items), PathSegment::Index(i)) => items.get(*i)?,
101 _ => return None,
102 };
103 }
104 Some(cur)
105 }
106 matches!(at(node, path).map(|n| &n.kind), Some(Kind::Object(_)))
107}
108
109impl Node {
110 fn from_json(value: &JsonValue) -> Node {
111 let kind = match value {
112 JsonValue::Null => Kind::Null,
113 JsonValue::Bool(b) => Kind::Bool(*b),
114 JsonValue::Number(n) => Kind::Number(n.clone()),
115 JsonValue::String(s) => Kind::String(s.clone()),
116 JsonValue::Array(items) => Kind::Array(items.iter().map(Node::from_json).collect()),
117 JsonValue::Object(map) => Kind::Object(
118 map.iter()
119 .map(|(k, v)| (k.clone(), Node::from_json(v)))
120 .collect(),
121 ),
122 };
123 Node { fill: false, kind }
124 }
125
126 fn to_json(&self) -> JsonValue {
127 match &self.kind {
128 Kind::Null => JsonValue::Null,
129 Kind::Bool(b) => JsonValue::Bool(*b),
130 Kind::Number(n) => JsonValue::Number(n.clone()),
131 Kind::String(s) => JsonValue::String(s.clone()),
132 Kind::Array(items) => JsonValue::Array(items.iter().map(Node::to_json).collect()),
133 Kind::Object(entries) => JsonValue::Object(
134 entries
135 .iter()
136 .map(|(k, n)| (k.clone(), n.to_json()))
137 .collect(),
138 ),
139 }
140 }
141}
142
143pub fn json_depth_exceeds(value: &serde_json::Value, max_depth: usize) -> bool {
168 use serde_json::Value;
169 let mut stack: Vec<(&Value, usize)> = vec![(value, 0)];
171 while let Some((v, depth)) = stack.pop() {
172 match v {
173 Value::Array(items) => {
174 if depth + 1 > max_depth {
175 return true;
176 }
177 stack.extend(items.iter().map(|c| (c, depth + 1)));
178 }
179 Value::Object(map) => {
180 if depth + 1 > max_depth {
181 return true;
182 }
183 stack.extend(map.values().map(|c| (c, depth + 1)));
184 }
185 _ => {}
186 }
187 }
188 false
189}
190
191pub(crate) fn depth_check_meta_map<E>(
198 map: serde_json::Map<String, serde_json::Value>,
199 on_too_deep: impl FnOnce(usize) -> E,
200) -> Result<serde_json::Map<String, serde_json::Value>, E> {
201 let max = crate::document::limits::MAX_YAML_DEPTH;
202 let as_value = serde_json::Value::Object(map);
203 if json_depth_exceeds(&as_value, max) {
204 return Err(on_too_deep(max));
205 }
206 let serde_json::Value::Object(map) = as_value else {
207 unreachable!("constructed as Object above")
208 };
209 Ok(map)
210}
211
212impl QuillValue {
213 fn from_node(node: Node) -> Self {
214 QuillValue {
215 node,
216 json: OnceLock::new(),
217 }
218 }
219
220 pub fn from_yaml_str(yaml_str: &str) -> Result<Self, serde_saphyr::Error> {
222 let json_val: serde_json::Value = serde_saphyr::from_str(yaml_str)?;
223 Ok(Self::from_json(json_val))
224 }
225
226 pub fn as_json(&self) -> &serde_json::Value {
231 self.json.get_or_init(|| self.node.to_json())
232 }
233
234 pub fn into_json(self) -> serde_json::Value {
236 match self.json.into_inner() {
237 Some(json) => json,
238 None => self.node.to_json(),
239 }
240 }
241
242 pub fn from_json(json_val: serde_json::Value) -> Self {
244 let node = Node::from_json(&json_val);
245 let json = OnceLock::new();
246 let _ = json.set(json_val);
253 QuillValue { node, json }
254 }
255
256 pub fn string(s: impl Into<String>) -> Self {
258 Self::from_json(serde_json::Value::String(s.into()))
259 }
260
261 pub fn integer(n: i64) -> Self {
263 Self::from_json(serde_json::Value::Number(n.into()))
264 }
265
266 pub fn bool(b: bool) -> Self {
268 Self::from_json(serde_json::Value::Bool(b))
269 }
270
271 pub fn null() -> Self {
273 Self::from_json(serde_json::Value::Null)
274 }
275
276 pub fn fill(&self) -> bool {
278 self.node.fill
279 }
280
281 pub fn fill_paths(&self) -> Vec<Vec<PathSegment>> {
286 let mut out = Vec::new();
287 let mut prefix = Vec::new();
288 collect_fill_paths(&self.node, &mut prefix, &mut out);
289 out
290 }
291
292 pub fn nonroot_fill_paths(&self) -> impl Iterator<Item = Vec<PathSegment>> {
297 self.fill_paths().into_iter().filter(|p| !p.is_empty())
298 }
299
300 pub fn set_fill_at(&mut self, path: &[PathSegment]) -> bool {
303 match node_at_mut(&mut self.node, path) {
304 Some(n) => {
305 n.fill = true;
306 true
307 }
308 None => false,
309 }
310 }
311
312 pub fn is_object_at(&self, path: &[PathSegment]) -> bool {
315 node_is_object(&self.node, path)
316 }
317}
318
319macro_rules! impl_from_scalar {
324 ($($ty:ty),* $(,)?) => {$(
325 impl From<$ty> for QuillValue {
326 fn from(v: $ty) -> Self {
327 QuillValue::from_json(serde_json::Value::from(v))
328 }
329 }
330 )*};
331}
332impl_from_scalar!(&str, String, bool, i32, i64, u32, u64, f64);
333
334impl From<serde_json::Value> for QuillValue {
335 fn from(v: serde_json::Value) -> Self {
336 QuillValue::from_json(v)
337 }
338}
339
340impl Deref for QuillValue {
341 type Target = serde_json::Value;
342
343 fn deref(&self) -> &Self::Target {
344 self.as_json()
345 }
346}
347
348impl PartialEq for QuillValue {
349 fn eq(&self, other: &Self) -> bool {
352 self.node == other.node
353 }
354}
355
356impl Clone for QuillValue {
357 fn clone(&self) -> Self {
358 let json = OnceLock::new();
359 if let Some(cached) = self.json.get() {
360 let _ = json.set(cached.clone());
361 }
362 QuillValue {
363 node: self.node.clone(),
364 json,
365 }
366 }
367}
368
369impl std::fmt::Debug for QuillValue {
370 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
371 if self.node.fill {
372 write!(f, "QuillValue(!must_fill {:?})", self.as_json())
373 } else {
374 write!(f, "QuillValue({:?})", self.as_json())
375 }
376 }
377}
378
379impl Serialize for QuillValue {
380 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
381 self.as_json().serialize(serializer)
382 }
383}
384
385impl<'de> Deserialize<'de> for QuillValue {
386 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
387 let json = serde_json::Value::deserialize(deserializer)?;
388 Ok(QuillValue::from_json(json))
389 }
390}
391
392impl QuillValue {
393 pub fn get(&self, key: &str) -> Option<QuillValue> {
401 match &self.node.kind {
402 Kind::Object(entries) => entries.get(key).map(|n| QuillValue::from_node(n.clone())),
403 _ => None,
404 }
405 }
406}
407
408#[cfg(test)]
409mod tests {
410 use super::*;
411
412 #[test]
413 fn test_from_yaml_str() {
414 let yaml_str = r#"
415 title: Test Document
416 author: John Doe
417 count: 42
418 "#;
419 let quill_val = QuillValue::from_yaml_str(yaml_str).unwrap();
420
421 assert_eq!(
422 quill_val.get("title").as_ref().and_then(|v| v.as_str()),
423 Some("Test Document")
424 );
425 assert_eq!(
426 quill_val.get("author").as_ref().and_then(|v| v.as_str()),
427 Some("John Doe")
428 );
429 assert_eq!(
430 quill_val.get("count").as_ref().and_then(|v| v.as_i64()),
431 Some(42)
432 );
433 }
434
435 #[test]
436 fn test_yaml_custom_tags_ignored_at_value_level() {
437 let yaml_str = "memo_from: !must_fill 2d lt example";
443 let quill_val = QuillValue::from_yaml_str(yaml_str).unwrap();
444
445 assert_eq!(
446 quill_val.get("memo_from").as_ref().and_then(|v| v.as_str()),
447 Some("2d lt example")
448 );
449 }
450
451 #[test]
452 fn json_round_trips_through_the_tree() {
453 let original = serde_json::json!({
456 "z": 1,
457 "a": [true, "x", 3.5, null],
458 "nested": { "k": 42 }
459 });
460 let qv = QuillValue::from_json(original.clone());
461 assert_eq!(qv.as_json(), &original);
462
463 let relowered = QuillValue::from_node(qv.node.clone()).into_json();
465 assert_eq!(relowered, original);
466 }
467
468 #[test]
469 fn depth_check_counts_empty_containers() {
470 use serde_json::json;
471
472 assert!(!json_depth_exceeds(&json!([]), 1));
477 assert!(!json_depth_exceeds(&json!({}), 1));
478 assert!(json_depth_exceeds(&json!([[]]), 1));
479 assert!(json_depth_exceeds(&json!({ "a": {} }), 1));
480
481 let deep_empty = |levels: usize| {
485 let mut v = serde_json::Value::Array(Vec::new());
486 for _ in 1..levels {
487 v = serde_json::Value::Array(vec![v]);
488 }
489 v
490 };
491 assert!(!json_depth_exceeds(&deep_empty(100), 100));
494 assert!(json_depth_exceeds(&deep_empty(101), 100));
495 }
496
497 #[test]
498 fn depth_check_counts_container_levels_not_the_scalar_leaf() {
499 let scalar_terminated = |levels: usize| {
506 let mut v = serde_json::json!(1);
507 for _ in 0..levels {
508 v = serde_json::json!({ "a": v });
509 }
510 v
511 };
512 assert!(!json_depth_exceeds(&scalar_terminated(100), 100));
513 assert!(json_depth_exceeds(&scalar_terminated(101), 100));
514
515 let container_terminated = |levels: usize| {
518 let mut v = serde_json::json!([1, 2, 3]);
519 for _ in 1..levels {
520 v = serde_json::json!({ "a": v });
521 }
522 v
523 };
524 assert!(!json_depth_exceeds(&container_terminated(100), 100));
525 assert!(json_depth_exceeds(&container_terminated(101), 100));
526 }
527
528 #[test]
529 fn fill_marker_rides_on_the_node_not_the_json() {
530 let filled = || {
531 let mut qv = QuillValue::string("draft");
532 assert!(qv.set_fill_at(&[]));
533 qv
534 };
535 let qv = filled();
536 assert!(qv.fill());
537 assert_eq!(qv.as_json(), &serde_json::json!("draft"));
539 assert_ne!(qv, QuillValue::string("draft"));
541 assert_eq!(qv, filled());
542 }
543}