rototo 0.1.0-alpha.8

Control plane for runtime configuration of your application.
Documentation
use crate::diagnostics::DiagnosticLocation;

use super::super::source::SourceDocument;

pub(crate) fn item_location(
    document: &SourceDocument,
    value: &::toml_span::Value<'_>,
) -> DiagnosticLocation {
    span_location(document, value_span(document, value))
}

pub(crate) fn table_location(
    document: &SourceDocument,
    value: &::toml_span::Value<'_>,
) -> DiagnosticLocation {
    span_location(document, value.span)
}

pub(crate) fn value_location(
    document: &SourceDocument,
    value: &::toml_span::Value<'_>,
) -> DiagnosticLocation {
    span_location(document, value_span(document, value))
}

fn span_location(document: &SourceDocument, span: ::toml_span::Span) -> DiagnosticLocation {
    let start = floor_char_boundary(&document.text, span.start.min(document.text.len()));
    let end = ceil_char_boundary(&document.text, span.end.min(document.text.len())).max(start);
    if start == end {
        document.document_location()
    } else {
        document.span_location(start..end)
    }
}

fn floor_char_boundary(text: &str, mut offset: usize) -> usize {
    while offset > 0 && !text.is_char_boundary(offset) {
        offset -= 1;
    }
    offset
}

fn ceil_char_boundary(text: &str, mut offset: usize) -> usize {
    while offset < text.len() && !text.is_char_boundary(offset) {
        offset += 1;
    }
    offset
}

fn value_span(document: &SourceDocument, value: &::toml_span::Value<'_>) -> ::toml_span::Span {
    if value.as_str().is_none() {
        return value.span;
    }

    let bytes = document.text.as_bytes();
    let mut start = value.span.start.min(bytes.len());
    let mut end = value.span.end.min(bytes.len()).max(start);
    if start == 0 || end >= bytes.len() {
        return ::toml_span::Span::new(start, end);
    }

    let quote = bytes[start - 1];
    if !matches!(quote, b'"' | b'\'') || bytes[end] != quote {
        return ::toml_span::Span::new(start, end);
    }

    while start > 0 && bytes[start - 1] == quote {
        start -= 1;
    }
    while end < bytes.len() && bytes[end] == quote {
        end += 1;
    }
    ::toml_span::Span::new(start, end)
}