1use std::{
5 fmt,
6 io::{Error, ErrorKind},
7};
8
9use tokio::io::{AsyncRead, AsyncWrite};
10
11use crate::{
12 serialize::{ByteRead, ByteWrite},
13 u8_repr_enum::U8ReprEnum,
14};
15
16pub const COMMENT_PREFIX_CHAR: char = '!';
18
19pub const ADMIN_PREFIX_CHAR: char = '@';
21
22pub const REGULAR_PREFIX_CHAR: char = '#';
24
25pub const ESCAPE_CHAR: char = '\\';
27
28pub const DEFAULT_USER_USERNAME: &str = "admin";
30
31pub const DEFAULT_USER_PASSWORD: &str = "admin";
33
34#[repr(u8)]
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum UserRole {
38 Admin = 0x01,
39 Regular = 0x02,
40}
41
42impl UserRole {
43 pub fn into_role_char(self) -> char {
44 match self {
45 Self::Admin => ADMIN_PREFIX_CHAR,
46 Self::Regular => REGULAR_PREFIX_CHAR,
47 }
48 }
49}
50
51impl U8ReprEnum for UserRole {
52 fn from_u8(value: u8) -> Option<Self> {
53 match value {
54 0x01 => Some(Self::Admin),
55 0x02 => Some(Self::Regular),
56 _ => None,
57 }
58 }
59
60 fn into_u8(self) -> u8 {
61 self as u8
62 }
63}
64
65impl ByteWrite for UserRole {
66 async fn write<W: AsyncWrite + Unpin + ?Sized>(&self, writer: &mut W) -> Result<(), Error> {
67 self.into_u8().write(writer).await
68 }
69}
70
71impl ByteRead for UserRole {
72 async fn read<R: AsyncRead + Unpin + ?Sized>(reader: &mut R) -> Result<Self, Error> {
73 match UserRole::from_u8(u8::read(reader).await?) {
74 Some(role) => Ok(role),
75 None => Err(Error::new(ErrorKind::InvalidData, "Invalid UserRole type byte")),
76 }
77 }
78}
79
80impl UserRole {
81 pub fn to_str(&self) -> &'static str {
83 match self {
84 Self::Admin => "admin",
85 Self::Regular => "regular",
86 }
87 }
88}
89
90impl fmt::Display for UserRole {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 write!(f, "{}", self.to_str())
93 }
94}
95
96#[derive(Debug)]
98pub enum UsersLoadingError {
99 IO(Error),
100 InvalidUtf8 { line_number: u32, byte_at: u64 },
101 LineTooLong { line_number: u32, byte_at: u64 },
102 ExpectedRoleCharGotEOF(u32, u32),
103 InvalidRoleChar(u32, u32, char),
104 ExpectedColonGotEOF(u32, u32),
105 EmptyUsername(u32, u32),
106 UsernameTooLong(u32, u32),
107 EmptyPassword(u32, u32),
108 PasswordTooLong(u32, u32),
109 NoUsers,
110}
111
112impl PartialEq for UsersLoadingError {
113 fn eq(&self, other: &Self) -> bool {
114 match self {
115 Self::IO(io_err) => {
116 if let Self::IO(other_err) = other {
117 io_err.kind() == other_err.kind()
118 } else {
119 false
120 }
121 }
122 Self::InvalidUtf8 { line_number, byte_at } => {
123 matches!(other, Self::InvalidUtf8 { line_number: a2, byte_at: b2 } if (line_number, byte_at) == (a2, b2))
124 }
125 Self::LineTooLong { line_number, byte_at } => {
126 matches!(other, Self::LineTooLong { line_number: a2, byte_at: b2 } if (line_number, byte_at) == (a2, b2))
127 }
128 Self::ExpectedRoleCharGotEOF(a, b) => matches!(other, Self::ExpectedRoleCharGotEOF(a2, b2) if (a, b) == (a2, b2)),
129 Self::InvalidRoleChar(a, b, c) => matches!(other, Self::InvalidRoleChar(a2, b2, c2) if (a, b, c) == (a2, b2, c2)),
130 Self::ExpectedColonGotEOF(a, b) => matches!(other, Self::ExpectedColonGotEOF(a2, b2) if (a, b) == (a2, b2)),
131 Self::EmptyUsername(a, b) => matches!(other, Self::EmptyUsername(a2, b2) if (a, b) == (a2, b2)),
132 Self::UsernameTooLong(a, b) => matches!(other, Self::UsernameTooLong(a2, b2) if (a, b) == (a2, b2)),
133 Self::EmptyPassword(a, b) => matches!(other, Self::EmptyPassword(a2, b2) if (a, b) == (a2, b2)),
134 Self::PasswordTooLong(a, b) => matches!(other, Self::PasswordTooLong(a2, b2) if (a, b) == (a2, b2)),
135 Self::NoUsers => matches!(other, Self::NoUsers),
136 }
137 }
138}
139
140impl From<Error> for UsersLoadingError {
141 fn from(value: Error) -> Self {
142 UsersLoadingError::IO(value)
143 }
144}
145
146impl fmt::Display for UsersLoadingError {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 match self {
149 UsersLoadingError::IO(io_error) => write!(f, "IO error: {io_error}"),
150 UsersLoadingError::InvalidUtf8 { line_number, byte_at } => write!(f, "Invalid UTF-8 at {line_number} byte {byte_at}"),
151 UsersLoadingError::LineTooLong { line_number, byte_at: _ } => write!(f, "Line {line_number} is too long"),
152 UsersLoadingError::ExpectedRoleCharGotEOF(line_number, char_at) => {
153 write!(f, "Expected role char, got EOF at {line_number}:{char_at}")
154 }
155 UsersLoadingError::InvalidRoleChar(line_number, char_at, char) => write!(
156 f,
157 "Expected role char ('{ADMIN_PREFIX_CHAR}' or '{REGULAR_PREFIX_CHAR}'), got '{char}' at {line_number}:{char_at}"
158 ),
159 UsersLoadingError::ExpectedColonGotEOF(line_number, char_at) => {
160 write!(f, "Unexpected EOF (expected colon ':' after name) at {line_number}:{char_at}")
161 }
162 UsersLoadingError::EmptyUsername(line_number, char_at) => write!(f, "Empty username field at {line_number}:{char_at}"),
163 UsersLoadingError::UsernameTooLong(line_number, char_at) => write!(f, "Username too long at {line_number}:{char_at}"),
164 UsersLoadingError::EmptyPassword(line_number, char_at) => write!(f, "Empty password field at {line_number}:{char_at}"),
165 UsersLoadingError::PasswordTooLong(line_number, char_at) => write!(f, "Password too long at {line_number}:{char_at}"),
166 UsersLoadingError::NoUsers => write!(f, "No users"),
167 }
168 }
169}
170
171impl ByteWrite for UsersLoadingError {
172 async fn write<W: AsyncWrite + Unpin + ?Sized>(&self, writer: &mut W) -> Result<(), Error> {
173 match self {
174 UsersLoadingError::IO(io_error) => (1u8, io_error).write(writer).await,
175 UsersLoadingError::InvalidUtf8 { line_number, byte_at } => (2u8, line_number, byte_at).write(writer).await,
176 UsersLoadingError::LineTooLong { line_number, byte_at } => (3u8, line_number, byte_at).write(writer).await,
177 UsersLoadingError::ExpectedRoleCharGotEOF(line_number, char_at) => (4u8, line_number, char_at).write(writer).await,
178 UsersLoadingError::InvalidRoleChar(line_number, char_at, char) => (5u8, line_number, char_at, *char).write(writer).await,
179 UsersLoadingError::ExpectedColonGotEOF(line_number, char_at) => (6u8, line_number, char_at).write(writer).await,
180 UsersLoadingError::EmptyUsername(line_number, char_at) => (7u8, line_number, char_at).write(writer).await,
181 UsersLoadingError::UsernameTooLong(line_number, char_at) => (8u8, line_number, char_at).write(writer).await,
182 UsersLoadingError::EmptyPassword(line_number, char_at) => (9u8, line_number, char_at).write(writer).await,
183 UsersLoadingError::PasswordTooLong(line_number, char_at) => (10u8, line_number, char_at).write(writer).await,
184 UsersLoadingError::NoUsers => 11u8.write(writer).await,
185 }
186 }
187}
188
189impl ByteRead for UsersLoadingError {
190 async fn read<R: AsyncRead + Unpin + ?Sized>(reader: &mut R) -> Result<Self, Error> {
191 let t = u8::read(reader).await?;
192
193 match t {
194 1 => Ok(UsersLoadingError::IO(Error::read(reader).await?)),
195 2 => Ok(UsersLoadingError::InvalidUtf8 {
196 line_number: u32::read(reader).await?,
197 byte_at: u64::read(reader).await?,
198 }),
199 3 => Ok(UsersLoadingError::LineTooLong {
200 line_number: u32::read(reader).await?,
201 byte_at: u64::read(reader).await?,
202 }),
203 4 => Ok(UsersLoadingError::ExpectedRoleCharGotEOF(
204 u32::read(reader).await?,
205 u32::read(reader).await?,
206 )),
207 5 => Ok(UsersLoadingError::InvalidRoleChar(
208 u32::read(reader).await?,
209 u32::read(reader).await?,
210 char::read(reader).await?,
211 )),
212 6 => Ok(UsersLoadingError::ExpectedColonGotEOF(
213 u32::read(reader).await?,
214 u32::read(reader).await?,
215 )),
216 7 => Ok(UsersLoadingError::EmptyUsername(u32::read(reader).await?, u32::read(reader).await?)),
217 8 => Ok(UsersLoadingError::UsernameTooLong(
218 u32::read(reader).await?,
219 u32::read(reader).await?,
220 )),
221 9 => Ok(UsersLoadingError::EmptyPassword(u32::read(reader).await?, u32::read(reader).await?)),
222 10 => Ok(UsersLoadingError::PasswordTooLong(
223 u32::read(reader).await?,
224 u32::read(reader).await?,
225 )),
226 11 => Ok(UsersLoadingError::NoUsers),
227 _ => Err(Error::new(ErrorKind::InvalidData, "Invalid UsersLoadingError type byte")),
228 }
229 }
230}