1use serde::{Deserialize, Serialize};
4
5use super::identity::{condition_identity, value_identity};
6use super::{
7 DeclarationProvenance, Program, ProgramProvenance, Value, ValueProvenance,
8 action_argument_values, fit, value_children,
9};
10use crate::source::{FileId, Position, SourceFile, Span};
11
12pub const TEXT_V1: &str = "workshop-rs/text-v1";
14
15pub const MAPPED_TEXT_V1: &str = "workshop-rs/mapped-text-v1";
18
19#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct SourceMap {
40 files: Vec<String>,
41 shape: Shape,
42 spans: Vec<MappedNode>,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq)]
48#[non_exhaustive]
49pub struct MappedText {
50 pub text: String,
52 pub map: SourceMap,
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
61#[non_exhaustive]
62pub enum SourceMapError {
63 GlobalVariableCount {
64 expected: usize,
65 found: usize,
66 },
67 PlayerVariableCount {
68 expected: usize,
69 found: usize,
70 },
71 SubroutineCount {
72 expected: usize,
73 found: usize,
74 },
75 RuleCount {
76 expected: usize,
77 found: usize,
78 },
79 ConditionCount {
80 rule: usize,
81 expected: usize,
82 found: usize,
83 },
84 ActionCount {
85 rule: usize,
86 expected: usize,
87 found: usize,
88 },
89 InvalidPosition,
91 DuplicateEntry,
93 EmptyEntry,
95 UnknownFile(usize),
97 InvalidSpan(Span),
99 UnsupportedFormat(String),
101 Malformed(String),
103}
104
105impl std::fmt::Display for SourceMapError {
106 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 let mismatch = |formatter: &mut std::fmt::Formatter<'_>, what, expected, found| {
108 write!(
109 formatter,
110 "source map shape mismatch: expected {expected} {what}, found {found}"
111 )
112 };
113 match self {
114 Self::GlobalVariableCount { expected, found } => {
115 mismatch(formatter, "global variables", expected, found)
116 }
117 Self::PlayerVariableCount { expected, found } => {
118 mismatch(formatter, "player variables", expected, found)
119 }
120 Self::SubroutineCount { expected, found } => {
121 mismatch(formatter, "subroutines", expected, found)
122 }
123 Self::RuleCount { expected, found } => mismatch(formatter, "rules", expected, found),
124 Self::ConditionCount {
125 rule,
126 expected,
127 found,
128 } => mismatch(
129 formatter,
130 &format!("conditions in rule {rule}"),
131 expected,
132 found,
133 ),
134 Self::ActionCount {
135 rule,
136 expected,
137 found,
138 } => mismatch(
139 formatter,
140 &format!("actions in rule {rule}"),
141 expected,
142 found,
143 ),
144 Self::InvalidPosition => {
145 write!(formatter, "source map entry is outside the program shape")
146 }
147 Self::DuplicateEntry => write!(formatter, "source map maps a node twice"),
148 Self::EmptyEntry => write!(formatter, "source map entry has no position"),
149 Self::UnknownFile(file) => {
150 write!(formatter, "source map span references unknown file {file}")
151 }
152 Self::InvalidSpan(span) => write!(formatter, "invalid source map span {span:?}"),
153 Self::UnsupportedFormat(format) => {
154 write!(formatter, "unsupported mapped text format {format:?}")
155 }
156 Self::Malformed(message) => write!(formatter, "malformed mapped text: {message}"),
157 }
158 }
159}
160
161impl std::error::Error for SourceMapError {}
162
163impl SourceMap {
164 pub fn extract(program: &Program) -> Self {
169 let mut spans = Vec::new();
170 push_declarations(
171 program,
172 &program.global_variables,
173 |provenance| &provenance.global_variables,
174 |index, span, name_span| MappedNode::GlobalVariable {
175 index,
176 span,
177 name_span,
178 },
179 &mut spans,
180 );
181 push_declarations(
182 program,
183 &program.player_variables,
184 |provenance| &provenance.player_variables,
185 |index, span, name_span| MappedNode::PlayerVariable {
186 index,
187 span,
188 name_span,
189 },
190 &mut spans,
191 );
192 push_declarations(
193 program,
194 &program.subroutines,
195 |provenance| &provenance.subroutines,
196 |index, span, name_span| MappedNode::Subroutine {
197 index,
198 span,
199 name_span,
200 },
201 &mut spans,
202 );
203 for (rule, public) in program.rules.iter().enumerate() {
204 if let Some(provenance) = program.rule_provenance(rule) {
205 if provenance.span.is_some()
206 || provenance.name.is_some()
207 || provenance.event_name.is_some()
208 {
209 spans.push(MappedNode::Rule {
210 rule,
211 span: provenance.span.map(WireSpan::from),
212 name_span: provenance.name.map(WireSpan::from),
213 event_name_span: provenance.event_name.map(WireSpan::from),
214 });
215 }
216 }
217 for (condition, public_condition) in public.conditions.iter().enumerate() {
218 let Some(record) = program.condition_record(rule, condition) else {
219 continue;
220 };
221 let children =
222 wire_children(&record.children, &value_children(&public_condition.value));
223 let (span, identifier) = if record.identity == condition_identity(public_condition)
224 {
225 (record.span, record.identifier)
226 } else {
227 Default::default()
228 };
229 if span.is_some() || identifier.is_some() || !children.is_empty() {
230 spans.push(MappedNode::Condition {
231 rule,
232 condition,
233 span: span.map(WireSpan::from),
234 identifier_span: identifier.map(WireSpan::from),
235 children,
236 });
237 }
238 }
239 for (action, public_action) in public.actions.iter().enumerate() {
240 if let Some(provenance) = program.action_provenance(rule, action) {
241 if provenance.span.is_some() || provenance.identifier.is_some() {
242 spans.push(MappedNode::Action {
243 rule,
244 action,
245 span: provenance.span.map(WireSpan::from),
246 identifier_span: provenance.identifier.map(WireSpan::from),
247 });
248 }
249 }
250 for (argument, value) in action_argument_values(public_action)
251 .iter()
252 .copied()
253 .enumerate()
254 {
255 let Some(record) = program.argument_record(rule, action, argument) else {
256 continue;
257 };
258 let children = wire_children(&record.children, &value_children(value));
259 let (span, identifier) = if record.identity == value_identity(value) {
260 (record.span, record.identifier)
261 } else {
262 Default::default()
263 };
264 if span.is_some() || identifier.is_some() || !children.is_empty() {
265 spans.push(MappedNode::ActionArgument {
266 rule,
267 action,
268 argument,
269 span: span.map(WireSpan::from),
270 identifier_span: identifier.map(WireSpan::from),
271 children,
272 });
273 }
274 }
275 }
276 }
277 Self {
278 files: program.files.iter().map(|file| file.path.clone()).collect(),
279 shape: Shape::of(program),
280 spans,
281 }
282 }
283
284 pub fn files(&self) -> &[String] {
286 &self.files
287 }
288
289 pub fn apply(&self, program: &mut Program) -> Result<(), SourceMapError> {
296 self.shape.check(program)?;
297
298 let mut provenance = ProgramProvenance::default();
299 fit(
300 &mut provenance.global_variables,
301 self.shape.global_variables,
302 );
303 fit(
304 &mut provenance.player_variables,
305 self.shape.player_variables,
306 );
307 fit(&mut provenance.subroutines, self.shape.subroutines);
308 fit(&mut provenance.rules, self.shape.rules.len());
309 for (rule, shape) in provenance.rules.iter_mut().zip(&self.shape.rules) {
310 fit(&mut rule.conditions, shape.conditions);
311 fit(&mut rule.actions, shape.actions);
312 }
313
314 for node in &self.spans {
315 match node {
316 MappedNode::GlobalVariable {
317 index,
318 span,
319 name_span,
320 } => {
321 let declaration = provenance
322 .global_variables
323 .get_mut(*index)
324 .ok_or(SourceMapError::InvalidPosition)?;
325 let mapped = self.declaration(*span, *name_span)?;
326 if declaration.span.is_some() || declaration.name_span.is_some() {
327 return Err(SourceMapError::DuplicateEntry);
328 }
329 *declaration = mapped;
330 }
331 MappedNode::PlayerVariable {
332 index,
333 span,
334 name_span,
335 } => {
336 let declaration = provenance
337 .player_variables
338 .get_mut(*index)
339 .ok_or(SourceMapError::InvalidPosition)?;
340 let mapped = self.declaration(*span, *name_span)?;
341 if declaration.span.is_some() || declaration.name_span.is_some() {
342 return Err(SourceMapError::DuplicateEntry);
343 }
344 *declaration = mapped;
345 }
346 MappedNode::Subroutine {
347 index,
348 span,
349 name_span,
350 } => {
351 let declaration = provenance
352 .subroutines
353 .get_mut(*index)
354 .ok_or(SourceMapError::InvalidPosition)?;
355 let mapped = self.declaration(*span, *name_span)?;
356 if declaration.span.is_some() || declaration.name_span.is_some() {
357 return Err(SourceMapError::DuplicateEntry);
358 }
359 *declaration = mapped;
360 }
361 MappedNode::Rule {
362 rule,
363 span,
364 name_span,
365 event_name_span,
366 } => {
367 let span = span.map(|span| self.span(span)).transpose()?;
368 let name = name_span.map(|span| self.span(span)).transpose()?;
369 let event_name = event_name_span.map(|span| self.span(span)).transpose()?;
370 let slot = provenance
371 .rules
372 .get_mut(*rule)
373 .ok_or(SourceMapError::InvalidPosition)?;
374 if slot.span.is_some() || slot.name.is_some() || slot.event_name.is_some() {
375 return Err(SourceMapError::DuplicateEntry);
376 }
377 if span.is_none() && name.is_none() && event_name.is_none() {
378 return Err(SourceMapError::EmptyEntry);
379 }
380 slot.span = span;
381 slot.name = name;
382 slot.event_name = event_name;
383 }
384 MappedNode::Condition {
385 rule,
386 condition,
387 span,
388 identifier_span,
389 children,
390 } => {
391 let span = span.map(|span| self.span(span)).transpose()?;
392 let identifier = identifier_span.map(|span| self.span(span)).transpose()?;
393 let has_children = children.iter().any(|child| !wire_value_unmapped(child));
394 let children = self.mapped_children(
395 children,
396 &program
397 .rules
398 .get(*rule)
399 .and_then(|rule| rule.conditions.get(*condition))
400 .ok_or(SourceMapError::InvalidPosition)?
401 .value,
402 )?;
403 let slot = provenance
404 .rules
405 .get_mut(*rule)
406 .and_then(|rule| rule.conditions.get_mut(*condition))
407 .ok_or(SourceMapError::InvalidPosition)?;
408 if slot.span.is_some() || slot.identifier.is_some() || !slot.children.is_empty()
409 {
410 return Err(SourceMapError::DuplicateEntry);
411 }
412 if span.is_none() && identifier.is_none() && !has_children {
413 return Err(SourceMapError::EmptyEntry);
414 }
415 slot.span = span;
416 slot.identifier = identifier;
417 slot.children = children;
418 }
419 MappedNode::Action {
420 rule,
421 action,
422 span,
423 identifier_span,
424 } => {
425 let span = span.map(|span| self.span(span)).transpose()?;
426 let identifier = identifier_span.map(|span| self.span(span)).transpose()?;
427 let slot = provenance
428 .rules
429 .get_mut(*rule)
430 .and_then(|rule| rule.actions.get_mut(*action))
431 .ok_or(SourceMapError::InvalidPosition)?;
432 if slot.span.is_some() || slot.identifier.is_some() {
433 return Err(SourceMapError::DuplicateEntry);
434 }
435 if span.is_none() && identifier.is_none() {
436 return Err(SourceMapError::EmptyEntry);
437 }
438 slot.span = span;
439 slot.identifier = identifier;
440 }
441 MappedNode::ActionArgument {
442 rule,
443 action,
444 argument,
445 span,
446 identifier_span,
447 children,
448 } => {
449 let span = span.map(|span| self.span(span)).transpose()?;
450 let identifier = identifier_span.map(|span| self.span(span)).transpose()?;
451 let argument_values = program
452 .rules
453 .get(*rule)
454 .and_then(|rule| rule.actions.get(*action))
455 .map(action_argument_values)
456 .ok_or(SourceMapError::InvalidPosition)?;
457 let Some(&value) = argument_values.get(*argument) else {
458 return Err(SourceMapError::InvalidPosition);
459 };
460 let count = argument_values.len();
461 let has_children = children.iter().any(|child| !wire_value_unmapped(child));
462 let children = self.mapped_children(children, value)?;
463 let arguments = &mut provenance
464 .rules
465 .get_mut(*rule)
466 .and_then(|rule| rule.actions.get_mut(*action))
467 .ok_or(SourceMapError::InvalidPosition)?
468 .arguments;
469 fit(arguments, count);
470 let slot = &mut arguments[*argument];
471 if slot.span.is_some() || slot.identifier.is_some() || !slot.children.is_empty()
472 {
473 return Err(SourceMapError::DuplicateEntry);
474 }
475 if span.is_none() && identifier.is_none() && !has_children {
476 return Err(SourceMapError::EmptyEntry);
477 }
478 slot.span = span;
479 slot.identifier = identifier;
480 slot.children = children;
481 }
482 }
483 }
484
485 program.files.clear();
486 for path in &self.files {
487 program.add_file(SourceFile::new(path.clone()));
488 }
489 if let Some(settings) = &mut program.settings {
495 settings.clear_spans();
496 }
497 program.provenance = Some(Box::new(provenance));
498 program.record_identities();
499 Ok(())
500 }
501
502 fn span(&self, wire: WireSpan) -> Result<Span, SourceMapError> {
503 if wire.file >= self.files.len() {
504 return Err(SourceMapError::UnknownFile(wire.file));
505 }
506 let span = Span::from(wire);
507 if !span.is_valid() {
508 return Err(SourceMapError::InvalidSpan(span));
509 }
510 Ok(span)
511 }
512
513 fn declaration(
514 &self,
515 span: Option<WireSpan>,
516 name_span: Option<WireSpan>,
517 ) -> Result<DeclarationProvenance, SourceMapError> {
518 if span.is_none() && name_span.is_none() {
519 return Err(SourceMapError::EmptyEntry);
520 }
521 Ok(DeclarationProvenance {
522 span: span.map(|span| self.span(span)).transpose()?,
523 name_span: name_span.map(|span| self.span(span)).transpose()?,
524 ..DeclarationProvenance::default()
525 })
526 }
527
528 fn mapped_children(
536 &self,
537 wire: &[WireValue],
538 value: &Value,
539 ) -> Result<Vec<ValueProvenance>, SourceMapError> {
540 let children = value_children(value);
541 let mut mapped = wire
542 .iter()
543 .zip(children.iter().copied())
544 .map(|(wire, value)| self.mapped_value(wire, value))
545 .collect::<Result<Vec<_>, _>>()?;
546 mapped.resize_with(children.len(), ValueProvenance::default);
547 Ok(mapped)
548 }
549
550 fn mapped_value(
551 &self,
552 wire: &WireValue,
553 value: &Value,
554 ) -> Result<ValueProvenance, SourceMapError> {
555 Ok(ValueProvenance {
556 span: wire.span.map(|span| self.span(span)).transpose()?,
557 identifier: wire
558 .identifier_span
559 .map(|span| self.span(span))
560 .transpose()?,
561 children: self.mapped_children(&wire.children, value)?,
562 ..ValueProvenance::default()
563 })
564 }
565}
566
567impl MappedText {
568 pub fn new(text: impl Into<String>, map: SourceMap) -> Self {
569 Self {
570 text: text.into(),
571 map,
572 }
573 }
574
575 pub fn to_json(&self) -> String {
577 let artifact = Artifact {
578 format: MAPPED_TEXT_V1.to_string(),
579 text: self.text.clone(),
580 files: self
581 .map
582 .files
583 .iter()
584 .map(|path| WireFile { path: path.clone() })
585 .collect(),
586 shape: self.map.shape.clone(),
587 spans: self.map.spans.clone(),
588 };
589 serde_json::to_string(&artifact).expect("mapped text serializes to JSON")
590 }
591
592 pub fn from_json(json: &str) -> Result<Self, SourceMapError> {
597 let value: serde_json::Value = serde_json::from_str(json)
598 .map_err(|error| SourceMapError::Malformed(error.to_string()))?;
599 match value.get("format").and_then(serde_json::Value::as_str) {
600 Some(MAPPED_TEXT_V1) => {}
601 Some(other) => return Err(SourceMapError::UnsupportedFormat(other.to_string())),
602 None => return Err(SourceMapError::Malformed("missing format".to_string())),
603 }
604 let artifact: Artifact = serde_json::from_value(value)
605 .map_err(|error| SourceMapError::Malformed(error.to_string()))?;
606 Ok(Self {
607 text: artifact.text,
608 map: SourceMap {
609 files: artifact.files.into_iter().map(|file| file.path).collect(),
610 shape: artifact.shape,
611 spans: artifact.spans,
612 },
613 })
614 }
615}
616
617fn wire_children(children: &[ValueProvenance], values: &[&Value]) -> Vec<WireValue> {
624 if children.len() != values.len() {
625 return Vec::new();
626 }
627 let mut wire: Vec<WireValue> = children
628 .iter()
629 .zip(values.iter().copied())
630 .map(|(child, value)| wire_value(child, value))
631 .collect();
632 let last = wire
633 .iter()
634 .rposition(|child| !wire_value_unmapped(child))
635 .map(|index| index + 1)
636 .unwrap_or(0);
637 wire.truncate(last);
638 wire
639}
640
641fn wire_value(provenance: &ValueProvenance, value: &Value) -> WireValue {
642 let (span, identifier) = if provenance.identity == value_identity(value) {
643 (provenance.span, provenance.identifier)
644 } else {
645 Default::default()
646 };
647 WireValue {
648 span: span.map(WireSpan::from),
649 identifier_span: identifier.map(WireSpan::from),
650 children: wire_children(&provenance.children, &value_children(value)),
651 }
652}
653
654fn wire_value_unmapped(value: &WireValue) -> bool {
656 value.span.is_none()
657 && value.identifier_span.is_none()
658 && value.children.iter().all(wire_value_unmapped)
659}
660
661fn push_declarations<T: std::fmt::Debug>(
662 program: &Program,
663 nodes: &[T],
664 recorded: impl Fn(&ProgramProvenance) -> &[DeclarationProvenance],
665 node: impl Fn(usize, Option<WireSpan>, Option<WireSpan>) -> MappedNode,
666 output: &mut Vec<MappedNode>,
667) {
668 for index in 0..nodes.len() {
669 let declaration = program.declaration_provenance(&recorded, nodes, index);
670 if declaration.span.is_some() || declaration.name_span.is_some() {
671 output.push(node(
672 index,
673 declaration.span.map(WireSpan::from),
674 declaration.name_span.map(WireSpan::from),
675 ));
676 }
677 }
678}
679
680#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
681struct Artifact {
682 format: String,
683 text: String,
684 files: Vec<WireFile>,
685 shape: Shape,
686 spans: Vec<MappedNode>,
687}
688
689#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
690struct WireFile {
691 path: String,
692}
693
694#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
695struct Shape {
696 global_variables: usize,
697 player_variables: usize,
698 subroutines: usize,
699 rules: Vec<RuleShape>,
700}
701
702#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
703struct RuleShape {
704 conditions: usize,
705 actions: usize,
706}
707
708impl Shape {
709 fn of(program: &Program) -> Self {
710 Self {
711 global_variables: program.global_variables.len(),
712 player_variables: program.player_variables.len(),
713 subroutines: program.subroutines.len(),
714 rules: program
715 .rules
716 .iter()
717 .map(|rule| RuleShape {
718 conditions: rule.conditions.len(),
719 actions: rule.actions.len(),
720 })
721 .collect(),
722 }
723 }
724
725 fn check(&self, program: &Program) -> Result<(), SourceMapError> {
726 let found = Self::of(program);
727 if self.global_variables != found.global_variables {
728 return Err(SourceMapError::GlobalVariableCount {
729 expected: self.global_variables,
730 found: found.global_variables,
731 });
732 }
733 if self.player_variables != found.player_variables {
734 return Err(SourceMapError::PlayerVariableCount {
735 expected: self.player_variables,
736 found: found.player_variables,
737 });
738 }
739 if self.subroutines != found.subroutines {
740 return Err(SourceMapError::SubroutineCount {
741 expected: self.subroutines,
742 found: found.subroutines,
743 });
744 }
745 if self.rules.len() != found.rules.len() {
746 return Err(SourceMapError::RuleCount {
747 expected: self.rules.len(),
748 found: found.rules.len(),
749 });
750 }
751 for (rule, (expected, found)) in self.rules.iter().zip(&found.rules).enumerate() {
752 if expected.conditions != found.conditions {
753 return Err(SourceMapError::ConditionCount {
754 rule,
755 expected: expected.conditions,
756 found: found.conditions,
757 });
758 }
759 if expected.actions != found.actions {
760 return Err(SourceMapError::ActionCount {
761 rule,
762 expected: expected.actions,
763 found: found.actions,
764 });
765 }
766 }
767 Ok(())
768 }
769}
770
771#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
772#[serde(tag = "node", rename_all = "snake_case")]
773enum MappedNode {
774 Rule {
775 rule: usize,
776 #[serde(default, skip_serializing_if = "Option::is_none")]
777 span: Option<WireSpan>,
778 #[serde(default, skip_serializing_if = "Option::is_none")]
779 name_span: Option<WireSpan>,
780 #[serde(default, skip_serializing_if = "Option::is_none")]
781 event_name_span: Option<WireSpan>,
782 },
783 Condition {
784 rule: usize,
785 condition: usize,
786 #[serde(default, skip_serializing_if = "Option::is_none")]
787 span: Option<WireSpan>,
788 #[serde(default, skip_serializing_if = "Option::is_none")]
789 identifier_span: Option<WireSpan>,
790 #[serde(default, skip_serializing_if = "Vec::is_empty")]
791 children: Vec<WireValue>,
792 },
793 Action {
794 rule: usize,
795 action: usize,
796 #[serde(default, skip_serializing_if = "Option::is_none")]
797 span: Option<WireSpan>,
798 #[serde(default, skip_serializing_if = "Option::is_none")]
799 identifier_span: Option<WireSpan>,
800 },
801 ActionArgument {
802 rule: usize,
803 action: usize,
804 argument: usize,
805 #[serde(default, skip_serializing_if = "Option::is_none")]
806 span: Option<WireSpan>,
807 #[serde(default, skip_serializing_if = "Option::is_none")]
808 identifier_span: Option<WireSpan>,
809 #[serde(default, skip_serializing_if = "Vec::is_empty")]
810 children: Vec<WireValue>,
811 },
812 GlobalVariable {
813 index: usize,
814 #[serde(default, skip_serializing_if = "Option::is_none")]
815 span: Option<WireSpan>,
816 #[serde(default, skip_serializing_if = "Option::is_none")]
817 name_span: Option<WireSpan>,
818 },
819 PlayerVariable {
820 index: usize,
821 #[serde(default, skip_serializing_if = "Option::is_none")]
822 span: Option<WireSpan>,
823 #[serde(default, skip_serializing_if = "Option::is_none")]
824 name_span: Option<WireSpan>,
825 },
826 Subroutine {
827 index: usize,
828 #[serde(default, skip_serializing_if = "Option::is_none")]
829 span: Option<WireSpan>,
830 #[serde(default, skip_serializing_if = "Option::is_none")]
831 name_span: Option<WireSpan>,
832 },
833}
834
835#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
838struct WireValue {
839 #[serde(default, skip_serializing_if = "Option::is_none")]
840 span: Option<WireSpan>,
841 #[serde(default, skip_serializing_if = "Option::is_none")]
842 identifier_span: Option<WireSpan>,
843 #[serde(default, skip_serializing_if = "Vec::is_empty")]
844 children: Vec<WireValue>,
845}
846
847#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
848struct WireSpan {
849 file: usize,
850 start: WirePosition,
851 end: WirePosition,
852}
853
854#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
855struct WirePosition {
856 line: u32,
857 column: u32,
858}
859
860impl From<Span> for WireSpan {
861 fn from(span: Span) -> Self {
862 Self {
863 file: span.file.index(),
864 start: span.start.into(),
865 end: span.end.into(),
866 }
867 }
868}
869
870impl From<WireSpan> for Span {
871 fn from(wire: WireSpan) -> Self {
872 Span::new(
873 FileId::from_index(wire.file),
874 wire.start.into(),
875 wire.end.into(),
876 )
877 }
878}
879
880impl From<Position> for WirePosition {
881 fn from(position: Position) -> Self {
882 Self {
883 line: position.line,
884 column: position.col,
885 }
886 }
887}
888
889impl From<WirePosition> for Position {
890 fn from(position: WirePosition) -> Self {
891 Position::new(position.line, position.column)
892 }
893}