1use core::fmt;
2use std::{num::ParseIntError, str::Utf8Error};
3
4use fluent_uri::{
5 error::{ParseError, ResolveError},
6 Uri,
7};
8
9#[derive(Debug)]
11pub enum Error {
12 Unretrievable {
14 uri: String,
15 source: Box<dyn std::error::Error + Send + Sync>,
16 },
17 PointerToNowhere { pointer: String },
19 InvalidPercentEncoding { pointer: String, source: Utf8Error },
21 InvalidArrayIndex {
23 pointer: String,
24 index: String,
25 source: ParseIntError,
26 },
27 NoSuchAnchor { anchor: String },
29 InvalidAnchor { anchor: String },
31 InvalidUri(UriError),
33 UnknownSpecification { specification: String },
35}
36
37impl Error {
38 pub(crate) fn pointer_to_nowhere(pointer: impl Into<String>) -> Error {
39 Error::PointerToNowhere {
40 pointer: pointer.into(),
41 }
42 }
43 pub(crate) fn invalid_percent_encoding(pointer: impl Into<String>, source: Utf8Error) -> Error {
44 Error::InvalidPercentEncoding {
45 pointer: pointer.into(),
46 source,
47 }
48 }
49 pub(crate) fn invalid_array_index(
50 pointer: impl Into<String>,
51 index: impl Into<String>,
52 source: ParseIntError,
53 ) -> Error {
54 Error::InvalidArrayIndex {
55 pointer: pointer.into(),
56 index: index.into(),
57 source,
58 }
59 }
60 pub(crate) fn invalid_anchor(anchor: impl Into<String>) -> Error {
61 Error::InvalidAnchor {
62 anchor: anchor.into(),
63 }
64 }
65 pub(crate) fn no_such_anchor(anchor: impl Into<String>) -> Error {
66 Error::NoSuchAnchor {
67 anchor: anchor.into(),
68 }
69 }
70 pub(crate) fn unknown_specification(specification: impl Into<String>) -> Error {
71 Error::UnknownSpecification {
72 specification: specification.into(),
73 }
74 }
75
76 pub(crate) fn unretrievable(
77 uri: impl Into<String>,
78 source: Box<dyn std::error::Error + Send + Sync>,
79 ) -> Error {
80 Error::Unretrievable {
81 uri: uri.into(),
82 source,
83 }
84 }
85
86 pub(crate) fn uri_parsing_error(uri: impl Into<String>, error: ParseError) -> Error {
87 Error::InvalidUri(UriError::Parse {
88 uri: uri.into(),
89 is_reference: false,
90 error,
91 })
92 }
93
94 pub(crate) fn uri_reference_parsing_error(uri: impl Into<String>, error: ParseError) -> Error {
95 Error::InvalidUri(UriError::Parse {
96 uri: uri.into(),
97 is_reference: true,
98 error,
99 })
100 }
101
102 pub(crate) fn uri_resolving_error(
103 uri: impl Into<String>,
104 base: Uri<&str>,
105 error: ResolveError,
106 ) -> Error {
107 Error::InvalidUri(UriError::Resolve {
108 uri: uri.into(),
109 base: base.to_owned(),
110 error,
111 })
112 }
113}
114
115impl fmt::Display for Error {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 match self {
118 Error::Unretrievable { uri, source } => {
119 f.write_fmt(format_args!("Resource '{uri}' is not present in a registry and retrieving it failed: {source}"))
120 },
121 Error::PointerToNowhere { pointer } => {
122 f.write_fmt(format_args!("Pointer '{pointer}' does not exist"))
123 }
124 Error::InvalidPercentEncoding { pointer, .. } => {
125 f.write_fmt(format_args!("Invalid percent encoding in pointer '{pointer}': the decoded bytes do not represent valid UTF-8"))
126 }
127 Error::InvalidArrayIndex { pointer, index, .. } => {
128 f.write_fmt(format_args!("Failed to parse array index '{index}' in pointer '{pointer}'"))
129 }
130 Error::NoSuchAnchor { anchor } => {
131 f.write_fmt(format_args!("Anchor '{anchor}' does not exist"))
132 }
133 Error::InvalidAnchor { anchor } => {
134 f.write_fmt(format_args!("Anchor '{anchor}' is invalid"))
135 }
136 Error::InvalidUri(error) => error.fmt(f),
137 Error::UnknownSpecification { specification } => {
138 f.write_fmt(format_args!("Unknown specification: {specification}"))
139 }
140 }
141 }
142}
143
144impl std::error::Error for Error {
145 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
146 match self {
147 Error::Unretrievable { source, .. } => Some(&**source),
148 Error::InvalidUri(error) => Some(error),
149 Error::InvalidPercentEncoding { source, .. } => Some(source),
150 Error::InvalidArrayIndex { source, .. } => Some(source),
151 _ => None,
152 }
153 }
154}
155
156#[derive(Debug)]
158pub enum UriError {
159 Parse {
160 uri: String,
161 is_reference: bool,
162 error: ParseError,
163 },
164 Resolve {
165 uri: String,
166 base: Uri<String>,
167 error: ResolveError,
168 },
169}
170
171impl fmt::Display for UriError {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 match self {
174 UriError::Parse {
175 uri,
176 is_reference,
177 error,
178 } => {
179 if *is_reference {
180 f.write_fmt(format_args!("Invalid URI reference '{uri}': {error}"))
181 } else {
182 f.write_fmt(format_args!("Invalid URI '{uri}': {error}"))
183 }
184 }
185 UriError::Resolve { uri, base, error } => f.write_fmt(format_args!(
186 "Failed to resolve '{uri}' against '{base}': {error}"
187 )),
188 }
189 }
190}
191
192impl std::error::Error for UriError {
193 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
194 match self {
195 UriError::Parse { error, .. } => Some(error),
196 UriError::Resolve { error, .. } => Some(error),
197 }
198 }
199}