1use yo_common::{Code, Error, Result};
65
66use crate::build::Builder;
67use crate::head::Kind;
68use crate::read::Value;
69
70#[derive(Debug, Clone, Copy)]
77pub enum Edit<'a> {
78 Set(&'a [u8]),
80 Remove,
86 Put(&'a [u8], &'a [u8]),
91 Splice {
97 at: usize,
99 take: usize,
101 put: &'a [&'a [u8]],
103 },
104}
105
106pub fn edit(root: &Value<'_>, at: &[(usize, Edit<'_>)]) -> Result<Vec<u8>> {
113 if at
114 .iter()
115 .any(|(off, e)| *off == 0 && matches!(e, Edit::Remove))
116 {
117 return Err(no_root());
118 }
119 let mut done = vec![false; at.len()];
120 let mut b = Builder::new();
121 write(root, root, at, &mut done, &mut b)?;
122 if done.contains(&false) {
123 return Err(stray());
124 }
125 Ok(b.finish()?.to_vec())
126}
127
128fn write(
131 root: &Value<'_>,
132 v: &Value<'_>,
133 at: &[(usize, Edit<'_>)],
134 done: &mut [bool],
135 b: &mut Builder,
136) -> Result<()> {
137 let off = v.offset_in(root).ok_or_else(stray)?;
138 let Some(what) = find(at, off) else {
139 if !inside(root, v, at)? {
140 return b.embed(v);
141 }
142 return match v.kind() {
143 Kind::Object => object(root, v, at, done, b),
144 Kind::Array => array(root, v, at, done, b),
145 _ => Err(stray()),
148 };
149 };
150 mark(at, done, off, off + v.encoded_len().ok_or_else(unreadable)?);
154 match what {
155 Edit::Set(bytes) => {
156 let new = Value::new(bytes)
157 .ok_or_else(|| Error::new(Code::Invalid, "the value written is not readable"))?;
158 b.embed(&new)
159 }
160 Edit::Remove => Err(no_root()),
164 Edit::Put(key, value) => put(root, v, key, value, at, done, b),
165 Edit::Splice {
166 at: from,
167 take,
168 put,
169 } => splice(root, v, Run { from, take, put }, at, done, b),
170 }
171}
172
173fn object(
175 root: &Value<'_>,
176 v: &Value<'_>,
177 at: &[(usize, Edit<'_>)],
178 done: &mut [bool],
179 b: &mut Builder,
180) -> Result<()> {
181 let interned = v.is_interned();
182 if interned {
183 b.begin_object_interned()?;
184 } else {
185 b.begin_object()?;
186 }
187 for i in 0..v.len() {
188 let child = v.at(i).ok_or_else(unreadable)?;
189 if skipped(root, &child, at, done)? {
190 continue;
191 }
192 if interned {
193 b.key_id(v.key_id_at(i).ok_or_else(unreadable)?)?;
194 } else {
195 b.key(v.key_at(i).ok_or_else(unreadable)?)?;
196 }
197 write(root, &child, at, done, b)?;
198 }
199 b.end_object()
200}
201
202fn array(
204 root: &Value<'_>,
205 v: &Value<'_>,
206 at: &[(usize, Edit<'_>)],
207 done: &mut [bool],
208 b: &mut Builder,
209) -> Result<()> {
210 b.begin_array()?;
211 for i in 0..v.len() {
212 let child = v.at(i).ok_or_else(unreadable)?;
213 if skipped(root, &child, at, done)? {
214 continue;
215 }
216 write(root, &child, at, done, b)?;
217 }
218 b.end_array()
219}
220
221fn put(
227 root: &Value<'_>,
228 v: &Value<'_>,
229 key: &[u8],
230 value: &[u8],
231 at: &[(usize, Edit<'_>)],
232 done: &mut [bool],
233 b: &mut Builder,
234) -> Result<()> {
235 if v.kind() != Kind::Object {
236 return Err(Error::new(
237 Code::Invalid,
238 "a key can only be put into an object",
239 ));
240 }
241 if v.is_interned() {
242 return Err(Error::new(
243 Code::Invalid,
244 "an object whose keys are interned needs the collection's key table to take a new key",
245 ));
246 }
247 let new = Value::new(value)
248 .ok_or_else(|| Error::new(Code::Invalid, "the value put is not readable"))?;
249 b.begin_object()?;
250 for i in 0..v.len() {
251 let child = v.at(i).ok_or_else(unreadable)?;
252 if skipped(root, &child, at, done)? {
253 continue;
254 }
255 b.key(v.key_at(i).ok_or_else(unreadable)?)?;
256 write(root, &child, at, done, b)?;
257 }
258 b.key(key)?;
262 b.embed(&new)?;
263 b.end_object()
264}
265
266struct Run<'a> {
268 from: usize,
270 take: usize,
272 put: &'a [&'a [u8]],
274}
275
276fn splice(
282 root: &Value<'_>,
283 v: &Value<'_>,
284 run: Run<'_>,
285 at: &[(usize, Edit<'_>)],
286 done: &mut [bool],
287 b: &mut Builder,
288) -> Result<()> {
289 if v.kind() != Kind::Array {
290 return Err(Error::new(
291 Code::Invalid,
292 "elements can only be spliced into an array",
293 ));
294 }
295 let n = v.len();
296 let from = run.from.min(n);
297 let end = from.saturating_add(run.take).min(n);
298 b.begin_array()?;
299 let kept = |i: usize, b: &mut Builder, done: &mut [bool]| -> Result<()> {
300 let child = v.at(i).ok_or_else(unreadable)?;
301 if skipped(root, &child, at, done)? {
302 return Ok(());
303 }
304 write(root, &child, at, done, b)
305 };
306 for i in 0..from {
307 kept(i, b, done)?;
308 }
309 for bytes in run.put {
310 let new = Value::new(bytes)
311 .ok_or_else(|| Error::new(Code::Invalid, "an element written is not readable"))?;
312 b.embed(&new)?;
313 }
314 for i in end..n {
315 kept(i, b, done)?;
316 }
317 b.end_array()
318}
319
320fn find<'e>(at: &[(usize, Edit<'e>)], off: usize) -> Option<Edit<'e>> {
326 at.iter().find(|(o, _)| *o == off).map(|(_, e)| *e)
327}
328
329fn mark(at: &[(usize, Edit<'_>)], done: &mut [bool], off: usize, end: usize) {
331 for (i, (o, _)) in at.iter().enumerate() {
332 if *o == off || (*o > off && *o < end) {
333 done[i] = true;
334 }
335 }
336}
337
338fn inside(root: &Value<'_>, v: &Value<'_>, at: &[(usize, Edit<'_>)]) -> Result<bool> {
340 let off = v.offset_in(root).ok_or_else(stray)?;
341 let end = off + v.encoded_len().ok_or_else(unreadable)?;
342 Ok(at.iter().any(|(o, _)| *o > off && *o < end))
343}
344
345fn skipped(
347 root: &Value<'_>,
348 child: &Value<'_>,
349 at: &[(usize, Edit<'_>)],
350 done: &mut [bool],
351) -> Result<bool> {
352 let off = child.offset_in(root).ok_or_else(stray)?;
353 if !matches!(find(at, off), Some(Edit::Remove)) {
354 return Ok(false);
355 }
356 mark(
357 at,
358 done,
359 off,
360 off + child.encoded_len().ok_or_else(unreadable)?,
361 );
362 Ok(true)
363}
364
365fn no_root() -> Error {
366 Error::new(
367 Code::Invalid,
368 "the whole document cannot be removed, only the key it is under",
369 )
370}
371
372fn stray() -> Error {
373 Error::new(
374 Code::Invalid,
375 "an offset that no value in this document begins at",
376 )
377}
378
379fn unreadable() -> Error {
380 Error::new(Code::Corrupt, "the document being edited is not readable")
381}
382
383#[cfg(test)]
384mod tests {
385 use super::*;
386 use crate::Path;
387 use crate::text::from_json;
388
389 fn hits(doc: &[u8], path: &[u8]) -> Vec<usize> {
391 let root = Value::new(doc).expect("readable");
392 let mut found = Vec::new();
393 Path::parse(path)
394 .expect("the path parses")
395 .select(&root, &mut found);
396 found
397 .iter()
398 .map(|v| v.offset_in(&root).expect("from this document"))
399 .collect()
400 }
401
402 fn changed(text: &str, path: &[u8], what: Edit<'_>) -> String {
404 let doc = from_json(text.as_bytes()).expect("the text parses");
405 let root = Value::new(&doc).expect("readable");
406 let at: Vec<_> = hits(&doc, path)
407 .into_iter()
408 .map(|off| (off, what))
409 .collect();
410 let after = edit(&root, &at).expect("the edit applies");
411 let out = Value::new(&after).expect("readable");
412 assert!(out.validate(), "the document that came out is whole");
413 String::from_utf8(out.to_json().expect("writable")).expect("UTF-8")
414 }
415
416 #[test]
417 fn a_value_is_replaced_wherever_the_path_names_it() {
418 let nine = from_json(b"9").expect("parses");
419 assert_eq!(
420 changed(r#"{"a":{"n":1},"b":{"n":2}}"#, b"$..n", Edit::Set(&nine)),
421 r#"{"a":{"n":9},"b":{"n":9}}"#
422 );
423 assert_eq!(
424 changed(r#"{"a":[1,2,3]}"#, b"$.a[*]", Edit::Set(&nine)),
425 r#"{"a":[9,9,9]}"#
426 );
427 assert_eq!(changed("[1,2]", b"$", Edit::Set(&nine)), "9");
428 }
429
430 #[test]
431 fn a_value_that_is_removed_leaves_no_hole() {
432 assert_eq!(
433 changed(r#"{"a":1,"bb":2,"cc":3}"#, b"$.bb", Edit::Remove),
434 r#"{"a":1,"cc":3}"#
435 );
436 assert_eq!(changed("[1,2,3]", b"$[1]", Edit::Remove), "[1,3]");
437 assert_eq!(changed("[1,2,3]", b"$[*]", Edit::Remove), "[]");
438 assert_eq!(
439 changed(r#"{"a":{"n":1},"b":{"n":2}}"#, b"$..n", Edit::Remove),
440 r#"{"a":{},"b":{}}"#
441 );
442 }
443
444 #[test]
445 fn a_removal_inside_a_removal_is_dropped_rather_than_refused() {
446 assert_eq!(
450 changed(r#"{"a":{"a":1},"b":2}"#, b"$..a", Edit::Remove),
451 r#"{"b":2}"#
452 );
453 }
454
455 #[test]
456 fn the_whole_document_cannot_be_removed() {
457 let doc = from_json(br#"{"a":1}"#).expect("parses");
458 let root = Value::new(&doc).expect("readable");
459 let why = edit(&root, &[(0, Edit::Remove)]).unwrap_err();
460 assert!(
461 why.message().contains("only the key it is under"),
462 "{}",
463 why.message()
464 );
465 }
466
467 #[test]
468 fn a_key_put_into_an_object_lands_in_key_order() {
469 let one = from_json(b"1").expect("parses");
470 assert_eq!(
471 changed(r#"{"aa":1,"cc":3}"#, b"$", Edit::Put(b"bb", &one)),
472 r#"{"aa":1,"bb":1,"cc":3}"#
473 );
474 assert_eq!(
476 changed(r#"{"aa":1,"cc":3}"#, b"$", Edit::Put(b"cc", &one)),
477 r#"{"aa":1,"cc":1}"#
478 );
479 assert_eq!(
482 changed(
483 r#"{"a":{"x":1},"b":{"x":2}}"#,
484 b"$.*",
485 Edit::Put(b"n", &one)
486 ),
487 r#"{"a":{"n":1,"x":1},"b":{"n":1,"x":2}}"#
488 );
489 }
490
491 #[test]
492 fn a_key_cannot_be_put_into_something_that_is_not_an_object() {
493 let one = from_json(b"1").expect("parses");
494 let doc = from_json(b"[1,2]").expect("parses");
495 let root = Value::new(&doc).expect("readable");
496 let why = edit(&root, &[(0, Edit::Put(b"a", &one))]).unwrap_err();
497 assert!(
498 why.message().contains("only be put into an object"),
499 "{}",
500 why.message()
501 );
502 }
503
504 #[test]
505 fn a_splice_covers_appending_inserting_popping_and_trimming() {
506 let seven = from_json(b"7").expect("parses");
507 let eight = from_json(b"8").expect("parses");
508 let put: &[&[u8]] = &[&seven, &eight];
509
510 let append = Edit::Splice {
511 at: usize::MAX,
512 take: 0,
513 put,
514 };
515 assert_eq!(changed("[1,2]", b"$", append), "[1,2,7,8]");
516
517 let insert = Edit::Splice {
518 at: 1,
519 take: 0,
520 put,
521 };
522 assert_eq!(changed("[1,2]", b"$", insert), "[1,7,8,2]");
523
524 let pop = Edit::Splice {
525 at: 2,
526 take: 1,
527 put: &[],
528 };
529 assert_eq!(changed("[1,2,3]", b"$", pop), "[1,2]");
530
531 let kept: &[&[u8]] = &[&seven];
533 let trim = Edit::Splice {
534 at: 0,
535 take: usize::MAX,
536 put: kept,
537 };
538 assert_eq!(changed("[1,2,3]", b"$", trim), "[7]");
539
540 let each = Edit::Splice {
542 at: 0,
543 take: 0,
544 put: kept,
545 };
546 assert_eq!(
547 changed(r#"{"a":[1],"b":[2]}"#, b"$..a", each),
548 r#"{"a":[7,1],"b":[2]}"#
549 );
550 }
551
552 #[test]
553 fn elements_cannot_be_spliced_into_something_that_is_not_an_array() {
554 let doc = from_json(br#"{"a":1}"#).expect("parses");
555 let root = Value::new(&doc).expect("readable");
556 let what = Edit::Splice {
557 at: 0,
558 take: 0,
559 put: &[],
560 };
561 let why = edit(&root, &[(0, what)]).unwrap_err();
562 assert!(
563 why.message().contains("only be spliced into an array"),
564 "{}",
565 why.message()
566 );
567 }
568
569 #[test]
570 fn everything_the_edit_did_not_name_comes_back_byte_identical() {
571 let text = br#"{"keep":[{"deep":[1,2,{"here":true}]},"text",null],"n":1.5,"go":0}"#;
572 let doc = from_json(text).expect("parses");
573 let root = Value::new(&doc).expect("readable");
574 let at: Vec<_> = hits(&doc, b"$.go")
575 .into_iter()
576 .map(|off| (off, Edit::Remove))
577 .collect();
578 let after = edit(&root, &at).expect("applies");
579
580 let out = Value::new(&after).expect("readable");
581 assert_eq!(
582 out.get(b"keep").expect("still there").as_bytes(),
583 root.get(b"keep").expect("was there").as_bytes(),
584 "the part nobody touched is the same bytes"
585 );
586 assert!(out.get(b"go").is_none());
587 assert_eq!(out.len(), 2);
588 }
589
590 #[test]
591 fn a_splice_or_a_put_still_carries_the_edits_inside_what_it_keeps() {
592 let one = from_json(b"1").expect("parses");
593 let put: &[&[u8]] = &[&one];
594 assert_eq!(
597 changed(
598 r#"{"a":[{"a":[7]}]}"#,
599 b"$..a",
600 Edit::Splice {
601 at: usize::MAX,
602 take: 0,
603 put,
604 }
605 ),
606 r#"{"a":[{"a":[7,1]},1]}"#
607 );
608 assert_eq!(
610 changed(
611 r#"{"o":{"o":{}}}"#,
612 b"$..o",
613 Edit::Put(b"n", one.as_slice())
614 ),
615 r#"{"o":{"n":1,"o":{"n":1}}}"#
616 );
617 assert_eq!(
620 changed(
621 r#"{"a":[{"a":[7]}]}"#,
622 b"$..a",
623 Edit::Splice {
624 at: 0,
625 take: usize::MAX,
626 put: &[],
627 }
628 ),
629 r#"{"a":[]}"#
630 );
631 }
632
633 #[test]
634 fn no_edits_at_all_is_the_document_it_was_given() {
635 let doc = from_json(br#"{"a":[1,{"b":"c"}],"d":null}"#).expect("parses");
636 let root = Value::new(&doc).expect("readable");
637 assert_eq!(edit(&root, &[]).expect("applies"), doc);
638 }
639
640 #[test]
641 fn an_offset_that_is_not_a_value_says_so() {
642 let doc = from_json(br#"{"a":1}"#).expect("parses");
643 let root = Value::new(&doc).expect("readable");
644 let one = from_json(b"1").expect("parses");
645 let why = edit(&root, &[(2, Edit::Set(&one))]).unwrap_err();
648 assert!(
649 why.message()
650 .contains("no value in this document begins at"),
651 "{}",
652 why.message()
653 );
654 let why = edit(&root, &[(doc.len() + 8, Edit::Set(&one))]).unwrap_err();
656 assert!(
657 why.message()
658 .contains("no value in this document begins at"),
659 "{}",
660 why.message()
661 );
662 }
663}