1use std::fmt::{self, Write};
3
4mod ast_id;
5mod hygiene;
6mod map;
7
8pub use self::{
9 ast_id::{AstIdMap, AstIdNode, ErasedFileAstId, FileAstId},
10 hygiene::{SyntaxContext, Transparency},
11 map::{RealSpanMap, SpanMap},
12};
13
14pub use syntax::Edition;
15pub use text_size::{TextRange, TextSize};
16pub use vfs::FileId;
17
18pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId = ErasedFileAstId::from_raw(0);
23
24pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId =
27 ErasedFileAstId::from_raw(!0 - 1);
30
31pub type Span = SpanData<SyntaxContext>;
32
33impl Span {
34 pub fn cover(self, other: Span) -> Span {
35 if self.anchor != other.anchor {
36 return self;
37 }
38 let range = self.range.cover(other.range);
39 Span { range, ..self }
40 }
41}
42
43#[derive(Clone, Copy, PartialEq, Eq, Hash)]
47pub struct SpanData<Ctx> {
48 pub range: TextRange,
52 pub anchor: SpanAnchor,
54 pub ctx: Ctx,
56}
57
58impl<Ctx: fmt::Debug> fmt::Debug for SpanData<Ctx> {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 if f.alternate() {
61 fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
62 f.write_char(':')?;
63 fmt::Debug::fmt(&self.anchor.ast_id.into_raw(), f)?;
64 f.write_char('@')?;
65 fmt::Debug::fmt(&self.range, f)?;
66 f.write_char('#')?;
67 self.ctx.fmt(f)
68 } else {
69 f.debug_struct("SpanData")
70 .field("range", &self.range)
71 .field("anchor", &self.anchor)
72 .field("ctx", &self.ctx)
73 .finish()
74 }
75 }
76}
77
78impl<Ctx: Copy> SpanData<Ctx> {
79 pub fn eq_ignoring_ctx(self, other: Self) -> bool {
80 self.anchor == other.anchor && self.range == other.range
81 }
82}
83
84impl fmt::Display for Span {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
87 f.write_char(':')?;
88 fmt::Debug::fmt(&self.anchor.ast_id.into_raw(), f)?;
89 f.write_char('@')?;
90 fmt::Debug::fmt(&self.range, f)?;
91 f.write_char('#')?;
92 self.ctx.fmt(f)
93 }
94}
95
96#[derive(Copy, Clone, PartialEq, Eq, Hash)]
97pub struct SpanAnchor {
98 pub file_id: EditionedFileId,
99 pub ast_id: ErasedFileAstId,
100}
101
102impl fmt::Debug for SpanAnchor {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 f.debug_tuple("SpanAnchor").field(&self.file_id).field(&self.ast_id.into_raw()).finish()
105 }
106}
107
108#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
111pub struct EditionedFileId(u32);
112
113impl fmt::Debug for EditionedFileId {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 f.debug_tuple("EditionedFileId")
116 .field(&self.file_id().index())
117 .field(&self.edition())
118 .finish()
119 }
120}
121
122impl From<EditionedFileId> for FileId {
123 fn from(value: EditionedFileId) -> Self {
124 value.file_id()
125 }
126}
127
128const _: () = assert!(
129 EditionedFileId::RESERVED_HIGH_BITS
130 + EditionedFileId::EDITION_BITS
131 + EditionedFileId::FILE_ID_BITS
132 == u32::BITS
133);
134const _: () = assert!(
135 EditionedFileId::RESERVED_MASK ^ EditionedFileId::EDITION_MASK ^ EditionedFileId::FILE_ID_MASK
136 == 0xFFFF_FFFF
137);
138
139impl EditionedFileId {
140 pub const RESERVED_MASK: u32 = 0x8000_0000;
141 pub const EDITION_MASK: u32 = 0x7F80_0000;
142 pub const FILE_ID_MASK: u32 = 0x007F_FFFF;
143
144 pub const MAX_FILE_ID: u32 = Self::FILE_ID_MASK;
145
146 pub const RESERVED_HIGH_BITS: u32 = Self::RESERVED_MASK.count_ones();
147 pub const FILE_ID_BITS: u32 = Self::FILE_ID_MASK.count_ones();
148 pub const EDITION_BITS: u32 = Self::EDITION_MASK.count_ones();
149
150 pub const fn current_edition(file_id: FileId) -> Self {
151 Self::new(file_id, Edition::CURRENT)
152 }
153
154 pub const fn new(file_id: FileId, edition: Edition) -> Self {
155 let file_id = file_id.index();
156 let edition = edition as u32;
157 assert!(file_id <= Self::MAX_FILE_ID);
158 Self(file_id | (edition << Self::FILE_ID_BITS))
159 }
160
161 pub fn from_raw(u32: u32) -> Self {
162 assert!(u32 & Self::RESERVED_MASK == 0);
163 assert!((u32 & Self::EDITION_MASK) >> Self::FILE_ID_BITS <= Edition::LATEST as u32);
164 Self(u32)
165 }
166
167 pub const fn as_u32(self) -> u32 {
168 self.0
169 }
170
171 pub const fn file_id(self) -> FileId {
172 FileId::from_raw(self.0 & Self::FILE_ID_MASK)
173 }
174
175 pub const fn unpack(self) -> (FileId, Edition) {
176 (self.file_id(), self.edition())
177 }
178
179 pub const fn edition(self) -> Edition {
180 let edition = (self.0 & Self::EDITION_MASK) >> Self::FILE_ID_BITS;
181 debug_assert!(edition <= Edition::LATEST as u32);
182 unsafe { std::mem::transmute(edition as u8) }
183 }
184}
185
186#[cfg(not(feature = "salsa"))]
187mod salsa {
188 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
189 pub struct Id(u32);
190}
191
192#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
210pub struct HirFileId(pub salsa::Id);
211
212#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
215pub struct MacroCallId(pub salsa::Id);
216
217#[derive(Clone, Copy, PartialEq, Eq, Hash)]
221pub struct TokenId(pub u32);
222
223impl std::fmt::Debug for TokenId {
224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225 self.0.fmt(f)
226 }
227}