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 {
395 pub fn is_null(&self) -> bool {
397 self.as_json().is_null()
398 }
399
400 pub fn as_str(&self) -> Option<&str> {
402 self.as_json().as_str()
403 }
404
405 pub fn as_bool(&self) -> Option<bool> {
407 self.as_json().as_bool()
408 }
409
410 pub fn as_i64(&self) -> Option<i64> {
412 self.as_json().as_i64()
413 }
414
415 pub fn as_u64(&self) -> Option<u64> {
417 self.as_json().as_u64()
418 }
419
420 pub fn as_f64(&self) -> Option<f64> {
422 self.as_json().as_f64()
423 }
424
425 pub fn as_array(&self) -> Option<&Vec<serde_json::Value>> {
427 self.as_json().as_array()
428 }
429
430 pub fn as_object(&self) -> Option<&serde_json::Map<String, serde_json::Value>> {
432 self.as_json().as_object()
433 }
434
435 pub fn get(&self, key: &str) -> Option<QuillValue> {
437 match &self.node.kind {
438 Kind::Object(entries) => entries.get(key).map(|n| QuillValue::from_node(n.clone())),
439 _ => None,
440 }
441 }
442}
443
444#[cfg(test)]
445mod tests {
446 use super::*;
447
448 #[test]
449 fn test_from_yaml_str() {
450 let yaml_str = r#"
451 title: Test Document
452 author: John Doe
453 count: 42
454 "#;
455 let quill_val = QuillValue::from_yaml_str(yaml_str).unwrap();
456
457 assert_eq!(
458 quill_val.get("title").as_ref().and_then(|v| v.as_str()),
459 Some("Test Document")
460 );
461 assert_eq!(
462 quill_val.get("author").as_ref().and_then(|v| v.as_str()),
463 Some("John Doe")
464 );
465 assert_eq!(
466 quill_val.get("count").as_ref().and_then(|v| v.as_i64()),
467 Some(42)
468 );
469 }
470
471 #[test]
472 fn test_yaml_custom_tags_ignored_at_value_level() {
473 let yaml_str = "memo_from: !must_fill 2d lt example";
479 let quill_val = QuillValue::from_yaml_str(yaml_str).unwrap();
480
481 assert_eq!(
482 quill_val.get("memo_from").as_ref().and_then(|v| v.as_str()),
483 Some("2d lt example")
484 );
485 }
486
487 #[test]
488 fn json_round_trips_through_the_tree() {
489 let original = serde_json::json!({
492 "z": 1,
493 "a": [true, "x", 3.5, null],
494 "nested": { "k": 42 }
495 });
496 let qv = QuillValue::from_json(original.clone());
497 assert_eq!(qv.as_json(), &original);
498
499 let relowered = QuillValue::from_node(qv.node.clone()).into_json();
501 assert_eq!(relowered, original);
502 }
503
504 #[test]
505 fn depth_check_counts_empty_containers() {
506 use serde_json::json;
507
508 assert!(!json_depth_exceeds(&json!([]), 1));
513 assert!(!json_depth_exceeds(&json!({}), 1));
514 assert!(json_depth_exceeds(&json!([[]]), 1));
515 assert!(json_depth_exceeds(&json!({ "a": {} }), 1));
516
517 let deep_empty = |levels: usize| {
521 let mut v = serde_json::Value::Array(Vec::new());
522 for _ in 1..levels {
523 v = serde_json::Value::Array(vec![v]);
524 }
525 v
526 };
527 assert!(!json_depth_exceeds(&deep_empty(100), 100));
530 assert!(json_depth_exceeds(&deep_empty(101), 100));
531 }
532
533 #[test]
534 fn depth_check_counts_container_levels_not_the_scalar_leaf() {
535 let scalar_terminated = |levels: usize| {
542 let mut v = serde_json::json!(1);
543 for _ in 0..levels {
544 v = serde_json::json!({ "a": v });
545 }
546 v
547 };
548 assert!(!json_depth_exceeds(&scalar_terminated(100), 100));
549 assert!(json_depth_exceeds(&scalar_terminated(101), 100));
550
551 let container_terminated = |levels: usize| {
554 let mut v = serde_json::json!([1, 2, 3]);
555 for _ in 1..levels {
556 v = serde_json::json!({ "a": v });
557 }
558 v
559 };
560 assert!(!json_depth_exceeds(&container_terminated(100), 100));
561 assert!(json_depth_exceeds(&container_terminated(101), 100));
562 }
563
564 #[test]
565 fn fill_marker_rides_on_the_node_not_the_json() {
566 let filled = || {
567 let mut qv = QuillValue::string("draft");
568 assert!(qv.set_fill_at(&[]));
569 qv
570 };
571 let qv = filled();
572 assert!(qv.fill());
573 assert_eq!(qv.as_json(), &serde_json::json!("draft"));
575 assert_ne!(qv, QuillValue::string("draft"));
577 assert_eq!(qv, filled());
578 }
579}