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