1#[cfg(feature = "huge_documents")]
2use serde_core::Deserializer;
3use serde_core::de::{self, IgnoredAny, MapAccess, Visitor};
4#[cfg(feature = "huge_documents")]
5use std::fmt;
6
7#[cfg(not(feature = "huge_documents"))]
8pub(crate) type SpanIndex = u32;
9
10#[cfg(not(feature = "huge_documents"))]
11const SPAN_INDEX_SENTINEL_VALUE: u64 = u32::MAX as u64;
12
13#[cfg(feature = "huge_documents")]
14const MAX_PACKED_SPAN_INDEX: u64 = (1u64 << 48) - 1;
15
16#[cfg(feature = "huge_documents")]
17const SPAN_INDEX_SENTINEL_VALUE: u64 = MAX_PACKED_SPAN_INDEX;
18
19const MAX_REPRESENTABLE_SPAN_INDEX_VALUE: u64 = SPAN_INDEX_SENTINEL_VALUE - 1;
20
21#[cfg(feature = "huge_documents")]
22#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
23pub(crate) struct SpanIndex([u8; 6]);
24
25#[cfg(feature = "huge_documents")]
26impl SpanIndex {
27 const fn from_u64_saturating(value: u64) -> Self {
28 let value = if value > MAX_PACKED_SPAN_INDEX {
29 MAX_PACKED_SPAN_INDEX
30 } else {
31 value
32 };
33
34 Self([
35 value as u8,
36 (value >> 8) as u8,
37 (value >> 16) as u8,
38 (value >> 24) as u8,
39 (value >> 32) as u8,
40 (value >> 40) as u8,
41 ])
42 }
43
44 const fn to_u64(self) -> u64 {
45 (self.0[0] as u64)
46 | ((self.0[1] as u64) << 8)
47 | ((self.0[2] as u64) << 16)
48 | ((self.0[3] as u64) << 24)
49 | ((self.0[4] as u64) << 32)
50 | ((self.0[5] as u64) << 40)
51 }
52}
53
54#[cfg(feature = "huge_documents")]
55impl fmt::Debug for SpanIndex {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 self.to_u64().fmt(f)
58 }
59}
60
61#[cfg(feature = "huge_documents")]
62impl<'de> serde_core::Deserialize<'de> for SpanIndex {
63 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
64 where
65 D: Deserializer<'de>,
66 {
67 Ok(Self::from_u64_saturating(u64::deserialize(deserializer)?))
68 }
69}
70
71#[cfg(not(feature = "huge_documents"))]
72const fn span_index_from_u64_saturating(value: u64) -> SpanIndex {
73 if value > MAX_REPRESENTABLE_SPAN_INDEX_VALUE {
74 MAX_REPRESENTABLE_SPAN_INDEX_VALUE as u32
75 } else {
76 value as u32
77 }
78}
79
80#[cfg(feature = "huge_documents")]
81const fn span_index_from_u64_saturating(value: u64) -> SpanIndex {
82 let value = if value > MAX_REPRESENTABLE_SPAN_INDEX_VALUE {
83 MAX_REPRESENTABLE_SPAN_INDEX_VALUE
84 } else {
85 value
86 };
87
88 SpanIndex::from_u64_saturating(value)
89}
90
91#[cfg(not(feature = "huge_documents"))]
92const SPAN_INDEX_SENTINEL: SpanIndex = u32::MAX;
93
94#[cfg(feature = "huge_documents")]
95const SPAN_INDEX_SENTINEL: SpanIndex = SpanIndex::from_u64_saturating(SPAN_INDEX_SENTINEL_VALUE);
96
97const BYTE_INFO_UNAVAILABLE: (SpanIndex, SpanIndex) = (SPAN_INDEX_SENTINEL, SPAN_INDEX_SENTINEL);
98
99#[cfg(not(feature = "huge_documents"))]
100const fn span_index_to_u64(value: SpanIndex) -> u64 {
101 value as u64
102}
103
104#[cfg(feature = "huge_documents")]
105const fn span_index_to_u64(value: SpanIndex) -> u64 {
106 value.to_u64()
107}
108
109#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
127pub struct Span {
128 offset: SpanIndex,
129 len: SpanIndex,
130 byte_info: (SpanIndex, SpanIndex),
131}
132
133impl Default for Span {
134 fn default() -> Self {
135 Self::UNKNOWN
136 }
137}
138
139impl<'de> serde_core::Deserialize<'de> for Span {
140 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
141 where
142 D: serde_core::Deserializer<'de>,
143 {
144 enum Field {
145 Offset,
146 Len,
147 ByteInfo,
148 Ignore,
149 }
150
151 impl<'de> serde_core::Deserialize<'de> for Field {
152 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
153 where
154 D: serde_core::Deserializer<'de>,
155 {
156 struct FieldVisitor;
157
158 impl Visitor<'_> for FieldVisitor {
159 type Value = Field;
160
161 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
162 f.write_str("a Span field")
163 }
164
165 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
166 where
167 E: de::Error,
168 {
169 Ok(match value {
170 "offset" => Field::Offset,
171 "len" => Field::Len,
172 "byte_info" => Field::ByteInfo,
173 _ => Field::Ignore,
174 })
175 }
176 }
177
178 deserializer.deserialize_identifier(FieldVisitor)
179 }
180 }
181
182 struct SpanVisitor;
183
184 impl<'de> Visitor<'de> for SpanVisitor {
185 type Value = Span;
186
187 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
188 f.write_str("a source span")
189 }
190
191 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
192 where
193 A: MapAccess<'de>,
194 {
195 let mut offset = None;
196 let mut len = None;
197 let mut byte_info = None;
198
199 while let Some(field) = map.next_key::<Field>()? {
200 match field {
201 Field::Offset => {
202 if offset.is_some() {
203 return Err(de::Error::duplicate_field("offset"));
204 }
205 offset = Some(map.next_value()?);
206 }
207 Field::Len => {
208 if len.is_some() {
209 return Err(de::Error::duplicate_field("len"));
210 }
211 len = Some(map.next_value()?);
212 }
213 Field::ByteInfo => {
214 if byte_info.is_some() {
215 return Err(de::Error::duplicate_field("byte_info"));
216 }
217 byte_info = Some(map.next_value()?);
218 }
219 Field::Ignore => {
220 let _ = map.next_value::<IgnoredAny>()?;
221 }
222 }
223 }
224
225 let offset = offset.ok_or_else(|| de::Error::missing_field("offset"))?;
226 let len = len.ok_or_else(|| de::Error::missing_field("len"))?;
227 let byte_info = byte_info.ok_or_else(|| de::Error::missing_field("byte_info"))?;
228
229 Ok(Span {
230 offset,
231 len,
232 byte_info,
233 })
234 }
235 }
236
237 const FIELDS: &[&str] = &["offset", "len", "byte_info"];
238 deserializer.deserialize_struct("Span", FIELDS, SpanVisitor)
239 }
240}
241
242impl Span {
243 pub const UNKNOWN: Self = Self {
245 offset: SPAN_INDEX_SENTINEL,
246 len: SPAN_INDEX_SENTINEL,
247 byte_info: BYTE_INFO_UNAVAILABLE,
248 };
249
250 #[must_use]
254 pub const fn new(offset: u64, len: u64) -> Self {
255 Self {
256 offset: span_index_from_u64_saturating(offset),
257 len: span_index_from_u64_saturating(len),
258 byte_info: BYTE_INFO_UNAVAILABLE,
259 }
260 }
261
262 #[must_use]
266 pub const fn with_byte_info(mut self, byte_offset: u64, byte_len: u64) -> Self {
267 self.byte_info = (
268 span_index_from_u64_saturating(byte_offset),
269 span_index_from_u64_saturating(byte_len),
270 );
271 self
272 }
273
274 #[inline]
276 #[must_use]
277 pub fn offset(&self) -> u64 {
278 span_index_to_u64(self.offset)
279 }
280
281 #[inline]
283 #[must_use]
284 pub fn len(&self) -> u64 {
285 span_index_to_u64(self.len)
286 }
287
288 #[inline]
291 #[must_use]
292 pub fn byte_offset(&self) -> Option<u64> {
293 if self.byte_info == BYTE_INFO_UNAVAILABLE {
294 None
295 } else {
296 Some(span_index_to_u64(self.byte_info.0))
297 }
298 }
299
300 #[inline]
303 #[must_use]
304 pub fn byte_len(&self) -> Option<u64> {
305 if self.byte_info == BYTE_INFO_UNAVAILABLE {
306 None
307 } else {
308 Some(span_index_to_u64(self.byte_info.1))
309 }
310 }
311
312 #[inline]
313 #[must_use]
314 pub fn is_empty(&self) -> bool {
315 self.len() == 0
316 }
317
318 #[cfg(feature = "deserialize")]
319 #[inline]
320 pub(crate) fn byte_info_or_unavailable(&self) -> (u64, u64) {
321 (
322 span_index_to_u64(self.byte_info.0),
323 span_index_to_u64(self.byte_info.1),
324 )
325 }
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331 #[cfg(feature = "huge_documents")]
332 use std::mem::size_of;
333
334 #[test]
335 fn span_constructors_round_trip_small_values() {
336 let span = Span::new(10, 5).with_byte_info(20, 5);
337 assert_eq!(span.offset(), 10);
338 assert_eq!(span.len(), 5);
339 assert_eq!(span.byte_offset(), Some(20));
340 assert_eq!(span.byte_len(), Some(5));
341 }
342
343 #[test]
344 fn unknown_span_has_no_byte_info() {
345 assert_eq!(Span::UNKNOWN.byte_offset(), None);
346 assert_eq!(Span::UNKNOWN.byte_len(), None);
347 assert_eq!(Span::UNKNOWN.offset(), SPAN_INDEX_SENTINEL_VALUE);
348 assert_eq!(Span::UNKNOWN.len(), SPAN_INDEX_SENTINEL_VALUE);
349 assert_eq!(Span::default(), Span::UNKNOWN);
350 }
351
352 #[test]
353 fn zero_length_span_at_offset_zero_is_not_unknown() {
354 let span = Span::new(0, 0);
355
356 assert_ne!(span, Span::UNKNOWN);
357 assert_eq!(span.offset(), 0);
358 assert_eq!(span.len(), 0);
359 assert!(span.is_empty());
360 assert_eq!(span.byte_offset(), None);
361 assert_eq!(span.byte_len(), None);
362 }
363
364 #[test]
365 fn byte_info_at_offset_zero_is_reportable() {
366 let span = Span::new(0, 0).with_byte_info(0, 0);
367
368 assert_ne!(span, Span::UNKNOWN);
369 assert_eq!(span.byte_offset(), Some(0));
370 assert_eq!(span.byte_len(), Some(0));
371 }
372
373 #[test]
374 fn constructor_values_saturate_below_unknown_sentinel() {
375 let span = Span::new(u64::MAX, u64::MAX).with_byte_info(u64::MAX, u64::MAX);
376
377 assert_ne!(span, Span::UNKNOWN);
378 assert_eq!(span.offset(), MAX_REPRESENTABLE_SPAN_INDEX_VALUE);
379 assert_eq!(span.len(), MAX_REPRESENTABLE_SPAN_INDEX_VALUE);
380 assert_eq!(span.byte_offset(), Some(MAX_REPRESENTABLE_SPAN_INDEX_VALUE));
381 assert_eq!(span.byte_len(), Some(MAX_REPRESENTABLE_SPAN_INDEX_VALUE));
382 }
383
384 #[test]
385 fn deserialize_span_accepts_unknown_fields() {
386 let span: Span = serde_json::from_str(
387 r#"{
388 "ignored": "value",
389 "offset": 10,
390 "len": 5,
391 "byte_info": [20, 5]
392 }"#,
393 )
394 .unwrap();
395
396 assert_eq!(span.offset(), 10);
397 assert_eq!(span.len(), 5);
398 assert_eq!(span.byte_offset(), Some(20));
399 assert_eq!(span.byte_len(), Some(5));
400 }
401
402 #[test]
403 fn deserialize_span_rejects_duplicate_fields() {
404 let err = serde_json::from_str::<Span>(
405 r#"{ "offset": 1, "offset": 2, "len": 3, "byte_info": [4, 5] }"#,
406 )
407 .unwrap_err();
408
409 assert!(err.to_string().contains("duplicate field `offset`"));
410 }
411
412 #[test]
413 fn deserialize_span_rejects_missing_fields() {
414 let err = serde_json::from_str::<Span>(r#"{ "offset": 1, "len": 2 }"#).unwrap_err();
415
416 assert!(err.to_string().contains("missing field `byte_info`"));
417 }
418
419 #[cfg(feature = "huge_documents")]
420 #[test]
421 fn huge_document_indices_saturate_to_48_bits() {
422 let span = Span::new(u64::MAX, u64::MAX).with_byte_info(u64::MAX, u64::MAX);
423 assert_eq!(span.offset(), MAX_PACKED_SPAN_INDEX - 1);
424 assert_eq!(span.len(), MAX_PACKED_SPAN_INDEX - 1);
425 assert_eq!(span.byte_offset(), Some(MAX_PACKED_SPAN_INDEX - 1));
426 assert_eq!(span.byte_len(), Some(MAX_PACKED_SPAN_INDEX - 1));
427 }
428
429 #[cfg(feature = "huge_documents")]
430 #[test]
431 fn huge_document_layout_stays_compact() {
432 assert_eq!(size_of::<Span>(), 24);
433 assert!(size_of::<crate::Location>() <= 40);
434 }
435
436 #[cfg(all(feature = "huge_documents", feature = "deserialize"))]
437 #[test]
438 fn huge_document_error_layout_stays_below_clippy_threshold() {
439 assert!(size_of::<crate::Error>() < 128);
440 }
441}