use saphyr_parser::Span as ParserSpan;
use serde::Deserialize;
#[cfg(not(feature = "huge_documents"))]
pub(crate) type SpanIndex = u32;
#[cfg(feature = "huge_documents")]
pub(crate) type SpanIndex = u64;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Default)]
pub struct Span {
pub(crate) offset: SpanIndex,
pub(crate) len: SpanIndex,
pub(crate) byte_info: (SpanIndex, SpanIndex),
}
impl Span {
pub const UNKNOWN: Self = Self {
offset: 0,
len: 0,
byte_info: (0, 0),
};
#[inline]
pub fn offset(&self) -> u64 {
#[cfg(not(feature = "huge_documents"))]
{
self.offset as u64
}
#[cfg(feature = "huge_documents")]
{
self.offset
}
}
#[inline]
pub fn len(&self) -> u64 {
#[cfg(not(feature = "huge_documents"))]
{
self.len as u64
}
#[cfg(feature = "huge_documents")]
{
self.len
}
}
#[inline]
pub fn byte_offset(&self) -> Option<u64> {
if self.byte_info == (0, 0) {
None
} else {
#[cfg(not(feature = "huge_documents"))]
{
Some(self.byte_info.0 as u64)
}
#[cfg(feature = "huge_documents")]
{
Some(self.byte_info.0)
}
}
}
#[inline]
pub fn byte_len(&self) -> Option<u64> {
if self.byte_info == (0, 0) {
None
} else {
#[cfg(not(feature = "huge_documents"))]
{
Some(self.byte_info.1 as u64)
}
#[cfg(feature = "huge_documents")]
{
Some(self.byte_info.1)
}
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub(crate) fn raw_offset(&self) -> SpanIndex {
self.offset
}
#[inline]
pub(crate) fn raw_len(&self) -> SpanIndex {
self.len
}
#[inline]
pub(crate) fn raw_byte_info(&self) -> (SpanIndex, SpanIndex) {
self.byte_info
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)]
pub struct Location {
pub(crate) line: u32,
pub(crate) column: u32,
#[serde(default)]
pub(crate) span: Span,
}
impl Location {
#[inline]
pub fn line(&self) -> u64 {
self.line as u64
}
#[inline]
pub fn column(&self) -> u64 {
self.column as u64
}
#[inline]
pub fn span(&self) -> Span {
self.span
}
}
impl Location {
pub const UNKNOWN: Self = Self {
line: 0,
column: 0,
span: Span::UNKNOWN,
};
pub(crate) const fn new(line: usize, column: usize) -> Self {
Self {
line: line as u32,
column: column as u32,
span: Span::UNKNOWN,
}
}
pub(crate) const fn with_span(mut self, span: Span) -> Self {
self.span = span;
self
}
}
pub(crate) fn location_from_span(span: &ParserSpan) -> Location {
let start = &span.start;
let end = &span.end;
let byte_info = if let (Some(start_byte), Some(end_byte)) = (start.byte_offset(), end.byte_offset()) {
#[cfg(not(feature = "huge_documents"))]
{
let len = end_byte.saturating_sub(start_byte);
if start_byte > (u32::MAX as usize) || len > (u32::MAX as usize) {
(0, 0)
} else {
(start_byte as SpanIndex, len as SpanIndex)
}
}
#[cfg(feature = "huge_documents")]
{
(start_byte as SpanIndex, (end_byte - start_byte) as SpanIndex)
}
} else {
(0, 0)
};
Location::new(start.line(), start.col() + 1).with_span(Span {
offset: start.index() as SpanIndex,
len: span.len() as SpanIndex,
byte_info,
})
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Locations {
pub reference_location: Location,
pub defined_location: Location,
}
impl Locations {
#[cfg_attr(not(any(feature = "garde", feature = "validator")), allow(dead_code))]
pub(crate) const UNKNOWN: Locations = Locations {
reference_location: Location::UNKNOWN,
defined_location: Location::UNKNOWN,
};
#[inline]
pub(crate) fn same(location: &Location) -> Option<Locations> {
if location == &Location::UNKNOWN {
None
} else {
Some(Locations {
reference_location: *location,
defined_location: *location,
})
}
}
#[inline]
pub fn primary_location(self) -> Option<Location> {
if self.reference_location != Location::UNKNOWN {
Some(self.reference_location)
} else if self.defined_location != Location::UNKNOWN {
Some(self.defined_location)
} else {
None
}
}
}