#[cfg(test)]
#[path = "./span_tests.rs"]
mod tests;
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
pub struct Span {
pub start: u32,
pub end: u32,
}
impl Span {
#[inline]
pub fn new(start: u32, end: u32) -> Self {
Self { start, end }
}
pub fn range(self) -> std::ops::Range<usize> {
self.start as usize..self.end as usize
}
#[inline]
pub fn is_empty(&self) -> bool {
self.start == 0 && self.end == 0
}
pub fn grow_key_to_header(&mut self, text: &[u8]) {
let mut start = self.start as usize;
while start > 0 && text[start - 1] != b'\n' {
start -= 1;
}
while text[start] != b'[' {
start += 1;
}
let end = find_header_end(text, start);
self.start = start as u32;
self.end = end as u32;
}
pub fn extract_header_span(&self, text: &[u8]) -> Span {
let start = self.start as usize;
let end = find_header_end(text, start);
Span::new(self.start, end as u32)
}
}
fn find_header_end(text: &[u8], start: usize) -> usize {
let mut pos = start;
debug_assert!(text[pos] == b'[');
pos += 1;
let is_aot = text[pos] == b'[';
if is_aot {
pos += 1;
}
loop {
match text[pos] {
b']' => {
pos += 1;
if is_aot {
pos += 1;
}
return pos;
}
b'"' => {
pos += 1;
while text[pos] != b'"' {
if text[pos] == b'\\' {
pos += 1;
}
pos += 1;
}
pos += 1;
}
b'\'' => {
pos += 1;
while text[pos] != b'\'' {
pos += 1;
}
pos += 1;
}
_ => pos += 1,
}
}
}
impl From<Span> for (u32, u32) {
fn from(s: Span) -> (u32, u32) {
(s.start, s.end)
}
}
impl From<Span> for (usize, usize) {
fn from(s: Span) -> (usize, usize) {
(s.start as usize, s.end as usize)
}
}
impl From<std::ops::Range<u32>> for Span {
fn from(s: std::ops::Range<u32>) -> Self {
Self::new(s.start, s.end)
}
}
impl From<Span> for std::ops::Range<u32> {
fn from(s: Span) -> Self {
s.start..s.end
}
}
impl From<Span> for std::ops::Range<usize> {
fn from(s: Span) -> Self {
s.start as usize..s.end as usize
}
}
pub struct Spanned<T> {
pub value: T,
pub span: Span,
}
impl<T> Spanned<T> {
#[inline]
pub const fn new(value: T) -> Self {
Self {
value,
span: Span { start: 0, end: 0 },
}
}
#[inline]
pub const fn with_span(value: T, span: Span) -> Self {
Self { value, span }
}
#[inline]
pub fn take(self) -> T {
self.value
}
#[inline]
pub fn map<V>(self) -> Spanned<V>
where
V: From<T>,
{
Spanned {
value: self.value.into(),
span: self.span,
}
}
}
impl<T> Default for Spanned<T>
where
T: Default,
{
fn default() -> Self {
Self {
value: Default::default(),
span: Span::default(),
}
}
}
impl<T> AsRef<T> for Spanned<T> {
fn as_ref(&self) -> &T {
&self.value
}
}
impl<T> std::fmt::Debug for Spanned<T>
where
T: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.value.fmt(f)
}
}
impl<T> Clone for Spanned<T>
where
T: Clone,
{
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
span: self.span,
}
}
}
impl<T> PartialOrd for Spanned<T>
where
T: PartialOrd,
{
fn partial_cmp(&self, o: &Spanned<T>) -> Option<std::cmp::Ordering> {
self.value.partial_cmp(&o.value)
}
}
impl<T> Ord for Spanned<T>
where
T: Ord,
{
fn cmp(&self, o: &Spanned<T>) -> std::cmp::Ordering {
self.value.cmp(&o.value)
}
}
impl<T> PartialEq for Spanned<T>
where
T: PartialEq,
{
fn eq(&self, o: &Spanned<T>) -> bool {
self.value == o.value
}
}
impl<T> Eq for Spanned<T> where T: Eq {}
impl<T> PartialEq<T> for Spanned<T>
where
T: PartialEq,
{
fn eq(&self, o: &T) -> bool {
&self.value == o
}
}
#[cfg(feature = "to-toml")]
impl<T: crate::ser::ToToml> crate::ser::ToToml for Spanned<T> {
fn to_toml<'a>(
&'a self,
arena: &'a crate::Arena,
) -> Result<crate::Item<'a>, crate::ser::ToTomlError> {
self.value.to_toml(arena)
}
}
#[cfg(feature = "from-toml")]
impl<'de, T> crate::de::FromToml<'de> for Spanned<T>
where
T: crate::de::FromToml<'de>,
{
#[inline]
fn from_toml(
ctx: &mut crate::de::Context<'de>,
value: &crate::item::Item<'de>,
) -> Result<Self, crate::de::Failed> {
let span = value.span_unchecked();
let inner = T::from_toml(ctx, value)?;
Ok(Self { span, value: inner })
}
}