1use std::fmt;
2
3pub type Result<T, E = Error> = std::result::Result<T, E>;
5
6#[derive(Debug)]
11pub enum Error {
12 Io(std::io::Error),
14 Config { file: String, line: usize, message: String },
16 Json { line: usize, column: usize, message: String },
18 Template { file: String, line: usize, column: usize, message: String },
23 Protocol(String),
25 Message(String),
27}
28
29impl Error {
30 pub fn msg(message: impl Into<String>) -> Self {
31 Error::Message(message.into())
32 }
33
34 pub fn status(&self) -> u16 {
36 match self {
37 Error::Protocol(_) => 400,
38 _ => 500,
39 }
40 }
41
42 pub fn title(&self) -> &'static str {
44 match self {
45 Error::Io(_) => "I/O Error",
46 Error::Config { .. } => "Configuration Error",
47 Error::Json { .. } => "JSON Error",
48 Error::Template { .. } => "Template Error",
49 Error::Protocol(_) => "Protocol Error",
50 Error::Message(_) => "Application Error",
51 }
52 }
53
54 pub fn hint(&self) -> Option<String> {
56 match self {
57 Error::Config { file, .. } => Some(format!(
58 "Check the syntax of `{file}`. Each line should look like `KEY=value`."
59 )),
60 Error::Json { .. } => {
61 Some("Verify the payload is valid JSON — trailing commas are not allowed.".into())
62 }
63 Error::Template { file, line, .. } => Some(format!(
64 "Look at `{file}` around line {line}. Every `@if`, `@foreach` and `@section` \
65 needs its matching `@end...`."
66 )),
67 Error::Io(e) if e.kind() == std::io::ErrorKind::NotFound => {
68 Some("The file does not exist. Did you run `rustlavel new` in this directory?".into())
69 }
70 Error::Io(e) if e.kind() == std::io::ErrorKind::AddrInUse => {
71 Some("That port is already in use. Try `rustlavel serve --port 8001`.".into())
72 }
73 _ => None,
74 }
75 }
76}
77
78impl fmt::Display for Error {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 match self {
81 Error::Io(e) => write!(f, "{e}"),
82 Error::Config { file, line, message } => {
83 write!(f, "{file}:{line}: {message}")
84 }
85 Error::Json { line, column, message } => {
86 write!(f, "invalid JSON at line {line}, column {column}: {message}")
87 }
88 Error::Template { file, line, column, message } => {
89 write!(f, "{file}:{line}:{column}: {message}")
90 }
91 Error::Protocol(m) => write!(f, "malformed request: {m}"),
92 Error::Message(m) => f.write_str(m),
93 }
94 }
95}
96
97impl std::error::Error for Error {
98 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
99 match self {
100 Error::Io(e) => Some(e),
101 _ => None,
102 }
103 }
104}
105
106impl From<std::io::Error> for Error {
107 fn from(e: std::io::Error) -> Self {
108 Error::Io(e)
109 }
110}
111
112impl From<String> for Error {
113 fn from(s: String) -> Self {
114 Error::Message(s)
115 }
116}
117
118impl From<&str> for Error {
119 fn from(s: &str) -> Self {
120 Error::Message(s.to_string())
121 }
122}