1use kernel::{AxCode, AxError};
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
20#[serde(try_from = "SpanFields", into = "SpanFields")]
21#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
22pub struct Span {
23 start: u64,
24 end: u64,
25}
26
27impl Span {
28 pub fn new(start: u64, end: u64) -> Result<Span, AxError> {
33 if start > end {
34 return Err(AxError::failure(
35 AxCode::InvalidArgs,
36 "name a stretch of a document",
37 format!("{start}..{end}"),
38 )
39 .with_recovery("give the start first: a span runs from its start up to its end"));
40 }
41 Ok(Span { start, end })
42 }
43
44 pub const fn at(at: u64) -> Span {
46 Span { start: at, end: at }
47 }
48
49 pub const fn start(self) -> u64 {
50 self.start
51 }
52
53 pub const fn end(self) -> u64 {
54 self.end
55 }
56
57 pub const fn len(self) -> u64 {
59 self.end.saturating_sub(self.start)
60 }
61
62 pub const fn is_empty(self) -> bool {
63 self.start == self.end
64 }
65
66 pub(crate) fn ordered(one: u64, other: u64) -> Span {
69 Span {
70 start: one.min(other),
71 end: one.max(other),
72 }
73 }
74
75 pub(crate) fn within(self, len: usize) -> Option<(usize, usize)> {
78 let start = usize::try_from(self.start).ok()?;
79 let end = usize::try_from(self.end).ok()?;
80 (end <= len).then_some((start, end))
81 }
82}
83
84pub(crate) fn offset(index: usize) -> u64 {
87 u64::try_from(index).unwrap_or(u64::MAX)
88}
89
90#[derive(Serialize, Deserialize)]
92#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
93#[cfg_attr(feature = "schema", schemars(rename = "Span"))]
94struct SpanFields {
95 start: u64,
96 end: u64,
97}
98
99impl TryFrom<SpanFields> for Span {
100 type Error = AxError;
101
102 fn try_from(fields: SpanFields) -> Result<Span, AxError> {
103 Span::new(fields.start, fields.end)
104 }
105}
106
107impl From<Span> for SpanFields {
108 fn from(span: Span) -> SpanFields {
109 SpanFields {
110 start: span.start,
111 end: span.end,
112 }
113 }
114}