nested-text 0.1.0

A fully spec-compliant NestedText v3.8 parser and serializer
Documentation
use std::fmt;

#[derive(Debug, Clone, PartialEq)]
pub enum ErrorKind {
    // Lexer errors
    InvalidIndentation,
    TabInIndentation,
    // Parser errors
    UnrecognizedLine,
    UnexpectedLineType,
    DuplicateKey,
    InvalidIndentLevel,
    // Inline errors
    UnterminatedInlineList,
    UnterminatedInlineDict,
    InvalidInlineCharacter,
    TrailingContent,
    // Dump errors
    UnsupportedType,
    // IO
    Io,
}

/// Error type with location information matching the NestedText test suite format.
#[derive(Debug, Clone)]
pub struct Error {
    pub kind: ErrorKind,
    pub message: String,
    /// 0-based line number where the error occurred.
    pub lineno: Option<usize>,
    /// 0-based column number where the error occurred.
    pub colno: Option<usize>,
    /// The source line that caused the error.
    pub line: Option<String>,
}

impl Error {
    pub fn new(kind: ErrorKind, message: impl Into<String>) -> Self {
        Error {
            kind,
            message: message.into(),
            lineno: None,
            colno: None,
            line: None,
        }
    }

    pub fn with_location(mut self, lineno: usize, colno: usize, line: impl Into<String>) -> Self {
        self.lineno = Some(lineno);
        self.colno = Some(colno);
        self.line = Some(line.into());
        self
    }

    pub fn with_lineno(mut self, lineno: usize) -> Self {
        self.lineno = Some(lineno);
        self
    }

    pub fn with_line(mut self, line: impl Into<String>) -> Self {
        self.line = Some(line.into());
        self
    }

    pub fn with_colno(mut self, colno: usize) -> Self {
        self.colno = Some(colno);
        self
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(lineno) = self.lineno {
            write!(f, "line {}: {}", lineno, self.message)
        } else {
            write!(f, "{}", self.message)
        }
    }
}

impl std::error::Error for Error {}

impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Self {
        Error::new(ErrorKind::Io, e.to_string())
    }
}