rio_turtle/
error.rs

1use crate::MAX_STACK_SIZE;
2use oxilangtag::LanguageTagParseError;
3use oxiri::IriParseError;
4use rio_api::parser::{LineBytePosition, ParseError};
5use std::char;
6use std::error::Error;
7use std::fmt;
8use std::io;
9
10/// Error that might be returned during parsing.
11///
12/// It might wrap an IO error or be a parsing error.
13#[derive(Debug)]
14pub struct TurtleError {
15    pub(crate) kind: TurtleErrorKind,
16    pub(crate) position: Option<LineBytePosition>,
17}
18
19#[derive(Debug)]
20pub enum TurtleErrorKind {
21    Io(io::Error),
22    UnknownPrefix(String),
23    PrematureEof,
24    UnexpectedByte(u8),
25    InvalidUnicodeCodePoint(u32),
26    InvalidIri {
27        iri: String,
28        error: IriParseError,
29    },
30    InvalidLanguageTag {
31        tag: String,
32        error: LanguageTagParseError,
33    },
34    StackOverflow,
35}
36
37impl fmt::Display for TurtleError {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        match &self.kind {
40            TurtleErrorKind::Io(error) => return error.fmt(f),
41            TurtleErrorKind::UnknownPrefix(prefix) => write!(f, "unknown prefix '{}'", prefix),
42            TurtleErrorKind::PrematureEof => write!(f, "premature end of file"),
43            TurtleErrorKind::UnexpectedByte(c) => match char::from_u32(u32::from(*c)) {
44                Some(c) => write!(f, "unexpected character '{}'", c.escape_debug()),
45                None => write!(f, "unexpected byter {}", c),
46            },
47            TurtleErrorKind::InvalidUnicodeCodePoint(point) => {
48                write!(f, "invalid unicode code point '{}'", point)
49            }
50            TurtleErrorKind::InvalidIri { iri, error } => {
51                write!(f, "error while parsing IRI '{}': {}", iri, error)
52            }
53            TurtleErrorKind::InvalidLanguageTag { tag, error } => {
54                write!(f, "error while parsing language tag '{}': {}", tag, error)
55            }
56            TurtleErrorKind::StackOverflow => {
57                write!(f, "The parser encountered more than {} nested constructions. This number is limited in order to avoid stack overflow OS errors.", MAX_STACK_SIZE)
58            }
59        }?;
60        if let Some(position) = self.position {
61            write!(
62                f,
63                " on line {} at position {}",
64                position.line_number(),
65                position.byte_number(),
66            )?;
67        }
68        Ok(())
69    }
70}
71
72impl Error for TurtleError {
73    fn source(&self) -> Option<&(dyn Error + 'static)> {
74        match &self.kind {
75            TurtleErrorKind::Io(error) => Some(error),
76            TurtleErrorKind::InvalidIri { error, .. } => Some(error),
77            TurtleErrorKind::InvalidLanguageTag { error, .. } => Some(error),
78            _ => None,
79        }
80    }
81}
82
83impl ParseError for TurtleError {
84    fn textual_position(&self) -> Option<LineBytePosition> {
85        self.position
86    }
87}
88
89impl From<io::Error> for TurtleError {
90    fn from(error: io::Error) -> Self {
91        Self {
92            kind: TurtleErrorKind::Io(error),
93            position: None,
94        }
95    }
96}
97
98impl From<TurtleError> for io::Error {
99    fn from(error: TurtleError) -> Self {
100        match error.kind {
101            TurtleErrorKind::Io(error) => error,
102            TurtleErrorKind::PrematureEof => io::Error::new(io::ErrorKind::UnexpectedEof, error),
103            _ => io::Error::new(io::ErrorKind::InvalidData, error),
104        }
105    }
106}