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