1use core::fmt;
24use core::marker::PhantomData;
25use std::collections::BTreeMap;
26
27use blazingly_json::Value;
28use serde::de::{DeserializeSeed, Deserializer, IgnoredAny, MapAccess, SeqAccess, Visitor};
29use serde::ser::SerializeMap;
30use serde::{Deserialize, Serialize, Serializer, de};
31
32use crate::{
33 model::{Completeness, EditPlan, FileEdit, TextEdit},
34 provenance::Provenance,
35};
36
37pub(crate) const TEXT_EDIT_FIELDS: [&str; 7] = [
39 "startLine",
40 "startChar",
41 "endLine",
42 "endChar",
43 "before",
44 "after",
45 "provenance",
46];
47
48pub(crate) const FILE_EDIT_FIELDS: [&str; 3] = ["path", "sha256", "edits"];
50
51pub(crate) const EDIT_PLAN_FIELDS: [&str; 4] =
53 ["schemaVersion", "operation", "files", "completeness"];
54
55trait ExtensionPolicy: Copy {
64 type Key;
66 type Sink;
68
69 fn key(name: &str) -> Self::Key;
70
71 fn sink() -> Self::Sink;
72
73 fn absorb<'de, A>(sink: &mut Self::Sink, key: Self::Key, map: &mut A) -> Result<(), A::Error>
75 where
76 A: MapAccess<'de>;
77
78 fn finish(sink: Self::Sink) -> BTreeMap<String, Value>;
79}
80
81#[derive(Clone, Copy)]
83struct Capture;
84
85impl ExtensionPolicy for Capture {
86 type Key = String;
87 type Sink = BTreeMap<String, Value>;
88
89 fn key(name: &str) -> String {
90 name.to_owned()
91 }
92
93 fn sink() -> Self::Sink {
94 BTreeMap::new()
95 }
96
97 fn absorb<'de, A>(sink: &mut Self::Sink, key: String, map: &mut A) -> Result<(), A::Error>
98 where
99 A: MapAccess<'de>,
100 {
101 sink.insert(key, map.next_value()?);
103 Ok(())
104 }
105
106 fn finish(sink: Self::Sink) -> BTreeMap<String, Value> {
107 sink
108 }
109}
110
111#[derive(Clone, Copy)]
113struct Discard;
114
115impl ExtensionPolicy for Discard {
116 type Key = ();
117 type Sink = ();
118
119 fn key(_name: &str) {}
120
121 fn sink() -> Self::Sink {}
122
123 fn absorb<'de, A>(_sink: &mut (), _key: (), map: &mut A) -> Result<(), A::Error>
124 where
125 A: MapAccess<'de>,
126 {
127 map.next_value::<IgnoredAny>()?;
128 Ok(())
129 }
130
131 fn finish((): Self::Sink) -> BTreeMap<String, Value> {
132 BTreeMap::new()
133 }
134}
135
136enum Field<K> {
141 Known(usize),
143 Unknown(K),
144}
145
146trait FieldTable {
152 fn lookup(name: &str) -> Option<usize>;
153}
154
155struct TextEditFields;
156
157impl FieldTable for TextEditFields {
158 fn lookup(name: &str) -> Option<usize> {
159 Some(match name {
160 "startLine" => 0,
161 "startChar" => 1,
162 "endLine" => 2,
163 "endChar" => 3,
164 "before" => 4,
165 "after" => 5,
166 "provenance" => 6,
167 _ => return None,
168 })
169 }
170}
171
172struct FileEditFields;
173
174impl FieldTable for FileEditFields {
175 fn lookup(name: &str) -> Option<usize> {
176 Some(match name {
177 "path" => 0,
178 "sha256" => 1,
179 "edits" => 2,
180 _ => return None,
181 })
182 }
183}
184
185struct EditPlanFields;
186
187impl FieldTable for EditPlanFields {
188 fn lookup(name: &str) -> Option<usize> {
189 Some(match name {
190 "schemaVersion" => 0,
191 "operation" => 1,
192 "files" => 2,
193 "completeness" => 3,
194 _ => return None,
195 })
196 }
197}
198
199struct FieldSeed<P, T>(PhantomData<(P, T)>);
200
201impl<P, T> Clone for FieldSeed<P, T> {
202 fn clone(&self) -> Self {
203 *self
204 }
205}
206
207impl<P, T> Copy for FieldSeed<P, T> {}
208
209impl<P, T> FieldSeed<P, T> {
210 const fn new() -> Self {
211 Self(PhantomData)
212 }
213}
214
215impl<'de, P: ExtensionPolicy, T: FieldTable> DeserializeSeed<'de> for FieldSeed<P, T> {
216 type Value = Field<P::Key>;
217
218 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
219 where
220 D: Deserializer<'de>,
221 {
222 deserializer.deserialize_identifier(self)
223 }
224}
225
226impl<P: ExtensionPolicy, T: FieldTable> Visitor<'_> for FieldSeed<P, T> {
227 type Value = Field<P::Key>;
228
229 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
230 formatter.write_str("field identifier")
231 }
232
233 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
234 where
235 E: de::Error,
236 {
237 Ok(match T::lookup(value) {
240 Some(index) => Field::Known(index),
241 None => Field::Unknown(P::key(value)),
242 })
243 }
244}
245
246struct VecSeed<S>(S);
252
253impl<'de, S> DeserializeSeed<'de> for VecSeed<S>
254where
255 S: DeserializeSeed<'de> + Copy,
256{
257 type Value = Vec<S::Value>;
258
259 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
260 where
261 D: Deserializer<'de>,
262 {
263 deserializer.deserialize_seq(self)
264 }
265}
266
267impl<'de, S> Visitor<'de> for VecSeed<S>
268where
269 S: DeserializeSeed<'de> + Copy,
270{
271 type Value = Vec<S::Value>;
272
273 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
274 formatter.write_str("a sequence")
275 }
276
277 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
278 where
279 A: SeqAccess<'de>,
280 {
281 let mut items = Vec::with_capacity(cautious_capacity::<S::Value>(seq.size_hint()));
282 while let Some(item) = seq.next_element_seed(self.0)? {
283 items.push(item);
284 }
285 Ok(items)
286 }
287}
288
289fn cautious_capacity<T>(hint: Option<usize>) -> usize {
293 const MAX_PREALLOCATED_BYTES: usize = 1024 * 1024;
294 MAX_PREALLOCATED_BYTES
295 .checked_div(size_of::<T>())
296 .map_or(0, |ceiling| hint.unwrap_or(0).min(ceiling))
297}
298
299struct TextEditSeed<P>(PhantomData<P>);
304
305impl<P> Clone for TextEditSeed<P> {
306 fn clone(&self) -> Self {
307 *self
308 }
309}
310
311impl<P> Copy for TextEditSeed<P> {}
312
313impl<P> TextEditSeed<P> {
314 const fn new() -> Self {
315 Self(PhantomData)
316 }
317}
318
319impl<'de, P: ExtensionPolicy> DeserializeSeed<'de> for TextEditSeed<P> {
320 type Value = TextEdit;
321
322 fn deserialize<D>(self, deserializer: D) -> Result<TextEdit, D::Error>
323 where
324 D: Deserializer<'de>,
325 {
326 deserializer.deserialize_map(self)
330 }
331}
332
333impl<'de, P: ExtensionPolicy> Visitor<'de> for TextEditSeed<P> {
334 type Value = TextEdit;
335
336 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
337 formatter.write_str("struct TextEdit")
338 }
339
340 fn visit_map<A>(self, mut map: A) -> Result<TextEdit, A::Error>
341 where
342 A: MapAccess<'de>,
343 {
344 let mut start_line: Option<u32> = None;
345 let mut start_char: Option<u32> = None;
346 let mut end_line: Option<u32> = None;
347 let mut end_char: Option<u32> = None;
348 let mut before: Option<String> = None;
349 let mut after: Option<String> = None;
350 let mut provenance: Option<Provenance> = None;
351 let mut sink = P::sink();
352
353 while let Some(field) = map.next_key_seed(FieldSeed::<P, TextEditFields>::new())? {
354 match field {
355 Field::Known(0) => {
356 if start_line.is_some() {
357 return Err(de::Error::duplicate_field("startLine"));
358 }
359 start_line = Some(map.next_value()?);
360 }
361 Field::Known(1) => {
362 if start_char.is_some() {
363 return Err(de::Error::duplicate_field("startChar"));
364 }
365 start_char = Some(map.next_value()?);
366 }
367 Field::Known(2) => {
368 if end_line.is_some() {
369 return Err(de::Error::duplicate_field("endLine"));
370 }
371 end_line = Some(map.next_value()?);
372 }
373 Field::Known(3) => {
374 if end_char.is_some() {
375 return Err(de::Error::duplicate_field("endChar"));
376 }
377 end_char = Some(map.next_value()?);
378 }
379 Field::Known(4) => {
380 if before.is_some() {
381 return Err(de::Error::duplicate_field("before"));
382 }
383 before = Some(map.next_value()?);
384 }
385 Field::Known(5) => {
386 if after.is_some() {
387 return Err(de::Error::duplicate_field("after"));
388 }
389 after = Some(map.next_value()?);
390 }
391 Field::Known(_) => {
393 if provenance.is_some() {
394 return Err(de::Error::duplicate_field("provenance"));
395 }
396 provenance = Some(map.next_value()?);
397 }
398 Field::Unknown(key) => P::absorb(&mut sink, key, &mut map)?,
399 }
400 }
401
402 Ok(TextEdit {
403 start_line: start_line.ok_or_else(|| de::Error::missing_field("startLine"))?,
404 start_char: start_char.ok_or_else(|| de::Error::missing_field("startChar"))?,
405 end_line: end_line.ok_or_else(|| de::Error::missing_field("endLine"))?,
406 end_char: end_char.ok_or_else(|| de::Error::missing_field("endChar"))?,
407 before: before.ok_or_else(|| de::Error::missing_field("before"))?,
408 after: after.ok_or_else(|| de::Error::missing_field("after"))?,
409 provenance: provenance.ok_or_else(|| de::Error::missing_field("provenance"))?,
410 extensions: P::finish(sink),
411 })
412 }
413}
414
415impl<'de> Deserialize<'de> for TextEdit {
416 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
417 where
418 D: Deserializer<'de>,
419 {
420 TextEditSeed::<Capture>::new().deserialize(deserializer)
421 }
422}
423
424impl Serialize for TextEdit {
425 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
426 where
427 S: Serializer,
428 {
429 let mut map = serializer.serialize_map(None)?;
432 map.serialize_entry(TEXT_EDIT_FIELDS[0], &self.start_line)?;
433 map.serialize_entry(TEXT_EDIT_FIELDS[1], &self.start_char)?;
434 map.serialize_entry(TEXT_EDIT_FIELDS[2], &self.end_line)?;
435 map.serialize_entry(TEXT_EDIT_FIELDS[3], &self.end_char)?;
436 map.serialize_entry(TEXT_EDIT_FIELDS[4], &self.before)?;
437 map.serialize_entry(TEXT_EDIT_FIELDS[5], &self.after)?;
438 map.serialize_entry(TEXT_EDIT_FIELDS[6], &self.provenance)?;
439 serialize_extensions(&mut map, &self.extensions)?;
440 map.end()
441 }
442}
443
444struct FileEditSeed<P>(PhantomData<P>);
449
450impl<P> Clone for FileEditSeed<P> {
451 fn clone(&self) -> Self {
452 *self
453 }
454}
455
456impl<P> Copy for FileEditSeed<P> {}
457
458impl<P> FileEditSeed<P> {
459 const fn new() -> Self {
460 Self(PhantomData)
461 }
462}
463
464impl<'de, P: ExtensionPolicy> DeserializeSeed<'de> for FileEditSeed<P> {
465 type Value = FileEdit;
466
467 fn deserialize<D>(self, deserializer: D) -> Result<FileEdit, D::Error>
468 where
469 D: Deserializer<'de>,
470 {
471 deserializer.deserialize_map(self)
472 }
473}
474
475impl<'de, P: ExtensionPolicy> Visitor<'de> for FileEditSeed<P> {
476 type Value = FileEdit;
477
478 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
479 formatter.write_str("struct FileEdit")
480 }
481
482 fn visit_map<A>(self, mut map: A) -> Result<FileEdit, A::Error>
483 where
484 A: MapAccess<'de>,
485 {
486 let mut path: Option<String> = None;
487 let mut sha256: Option<String> = None;
488 let mut edits: Option<Vec<TextEdit>> = None;
489 let mut sink = P::sink();
490
491 while let Some(field) = map.next_key_seed(FieldSeed::<P, FileEditFields>::new())? {
492 match field {
493 Field::Known(0) => {
494 if path.is_some() {
495 return Err(de::Error::duplicate_field("path"));
496 }
497 path = Some(map.next_value()?);
498 }
499 Field::Known(1) => {
500 if sha256.is_some() {
501 return Err(de::Error::duplicate_field("sha256"));
502 }
503 sha256 = Some(map.next_value()?);
504 }
505 Field::Known(_) => {
506 if edits.is_some() {
507 return Err(de::Error::duplicate_field("edits"));
508 }
509 edits = Some(map.next_value_seed(VecSeed(TextEditSeed::<P>::new()))?);
510 }
511 Field::Unknown(key) => P::absorb(&mut sink, key, &mut map)?,
512 }
513 }
514
515 Ok(FileEdit {
516 path: path.ok_or_else(|| de::Error::missing_field("path"))?,
517 sha256: sha256.ok_or_else(|| de::Error::missing_field("sha256"))?,
518 edits: edits.ok_or_else(|| de::Error::missing_field("edits"))?,
519 extensions: P::finish(sink),
520 })
521 }
522}
523
524impl<'de> Deserialize<'de> for FileEdit {
525 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
526 where
527 D: Deserializer<'de>,
528 {
529 FileEditSeed::<Capture>::new().deserialize(deserializer)
530 }
531}
532
533impl Serialize for FileEdit {
534 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
535 where
536 S: Serializer,
537 {
538 let mut map = serializer.serialize_map(None)?;
539 map.serialize_entry(FILE_EDIT_FIELDS[0], &self.path)?;
540 map.serialize_entry(FILE_EDIT_FIELDS[1], &self.sha256)?;
541 map.serialize_entry(FILE_EDIT_FIELDS[2], &self.edits)?;
542 serialize_extensions(&mut map, &self.extensions)?;
543 map.end()
544 }
545}
546
547struct EditPlanSeed<P>(PhantomData<P>);
552
553impl<P> Clone for EditPlanSeed<P> {
554 fn clone(&self) -> Self {
555 *self
556 }
557}
558
559impl<P> Copy for EditPlanSeed<P> {}
560
561impl<P> EditPlanSeed<P> {
562 const fn new() -> Self {
563 Self(PhantomData)
564 }
565}
566
567impl<'de, P: ExtensionPolicy> DeserializeSeed<'de> for EditPlanSeed<P> {
568 type Value = EditPlan;
569
570 fn deserialize<D>(self, deserializer: D) -> Result<EditPlan, D::Error>
571 where
572 D: Deserializer<'de>,
573 {
574 deserializer.deserialize_map(self)
575 }
576}
577
578impl<'de, P: ExtensionPolicy> Visitor<'de> for EditPlanSeed<P> {
579 type Value = EditPlan;
580
581 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
582 formatter.write_str("struct EditPlan")
583 }
584
585 fn visit_map<A>(self, mut map: A) -> Result<EditPlan, A::Error>
586 where
587 A: MapAccess<'de>,
588 {
589 let mut schema_version: Option<String> = None;
590 let mut operation: Option<String> = None;
591 let mut files: Option<Vec<FileEdit>> = None;
592 let mut completeness: Option<Option<Completeness>> = None;
595 let mut sink = P::sink();
596
597 while let Some(field) = map.next_key_seed(FieldSeed::<P, EditPlanFields>::new())? {
598 match field {
599 Field::Known(0) => {
600 if schema_version.is_some() {
601 return Err(de::Error::duplicate_field("schemaVersion"));
602 }
603 schema_version = Some(map.next_value()?);
604 }
605 Field::Known(1) => {
606 if operation.is_some() {
607 return Err(de::Error::duplicate_field("operation"));
608 }
609 operation = Some(map.next_value()?);
610 }
611 Field::Known(2) => {
612 if files.is_some() {
613 return Err(de::Error::duplicate_field("files"));
614 }
615 files = Some(map.next_value_seed(VecSeed(FileEditSeed::<P>::new()))?);
616 }
617 Field::Known(_) => {
618 if completeness.is_some() {
619 return Err(de::Error::duplicate_field("completeness"));
620 }
621 completeness = Some(map.next_value()?);
622 }
623 Field::Unknown(key) => P::absorb(&mut sink, key, &mut map)?,
624 }
625 }
626
627 Ok(EditPlan {
628 schema_version: schema_version
629 .ok_or_else(|| de::Error::missing_field("schemaVersion"))?,
630 operation: operation.ok_or_else(|| de::Error::missing_field("operation"))?,
631 files: files.ok_or_else(|| de::Error::missing_field("files"))?,
632 completeness: completeness.unwrap_or_default(),
633 extensions: P::finish(sink),
634 })
635 }
636}
637
638impl<'de> Deserialize<'de> for EditPlan {
639 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
640 where
641 D: Deserializer<'de>,
642 {
643 EditPlanSeed::<Capture>::new().deserialize(deserializer)
644 }
645}
646
647impl Serialize for EditPlan {
648 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
649 where
650 S: Serializer,
651 {
652 let mut map = serializer.serialize_map(None)?;
653 map.serialize_entry(EDIT_PLAN_FIELDS[0], &self.schema_version)?;
654 map.serialize_entry(EDIT_PLAN_FIELDS[1], &self.operation)?;
655 map.serialize_entry(EDIT_PLAN_FIELDS[2], &self.files)?;
656 if self.completeness.is_some() {
657 map.serialize_entry(EDIT_PLAN_FIELDS[3], &self.completeness)?;
658 }
659 serialize_extensions(&mut map, &self.extensions)?;
660 map.end()
661 }
662}
663
664fn serialize_extensions<M>(
668 map: &mut M,
669 extensions: &BTreeMap<String, Value>,
670) -> Result<(), M::Error>
671where
672 M: SerializeMap,
673{
674 for (key, value) in extensions {
675 map.serialize_entry(key, value)?;
676 }
677 Ok(())
678}
679
680#[derive(Clone, Debug, PartialEq)]
733pub struct DeclaredEditPlan(EditPlan);
734
735impl DeclaredEditPlan {
736 #[must_use]
738 pub const fn plan(&self) -> &EditPlan {
739 &self.0
740 }
741
742 #[must_use]
744 pub fn into_plan(self) -> EditPlan {
745 self.0
746 }
747}
748
749impl AsRef<EditPlan> for DeclaredEditPlan {
750 fn as_ref(&self) -> &EditPlan {
751 &self.0
752 }
753}
754
755impl From<DeclaredEditPlan> for EditPlan {
756 fn from(declared: DeclaredEditPlan) -> Self {
757 declared.0
758 }
759}
760
761impl<'de> Deserialize<'de> for DeclaredEditPlan {
762 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
763 where
764 D: Deserializer<'de>,
765 {
766 EditPlanSeed::<Discard>::new()
767 .deserialize(deserializer)
768 .map(Self)
769 }
770}
771
772#[cfg(test)]
773mod tests {
774 use super::{EDIT_PLAN_FIELDS, FILE_EDIT_FIELDS, TEXT_EDIT_FIELDS};
775 use crate::validation::FILE_EDIT_RESERVED_EXTENSION_KEYS;
776
777 #[test]
778 fn reserved_extension_keys_track_the_wire_field_names() {
779 assert_eq!(FILE_EDIT_RESERVED_EXTENSION_KEYS, FILE_EDIT_FIELDS);
783 assert_eq!(FILE_EDIT_FIELDS.len(), 3);
784 assert_eq!(TEXT_EDIT_FIELDS.len(), 7);
785 assert_eq!(EDIT_PLAN_FIELDS.len(), 4);
786 }
787}