aboutsummaryrefslogtreecommitdiff
path: root/src/field/mod.rs
diff options
context:
space:
mode:
authorRuben Beltran del Rio <git@r.bdr.sh>2025-02-09 23:17:22 +0100
committerRuben Beltran del Rio <git@r.bdr.sh>2025-02-09 23:17:22 +0100
commitcf94c0cc512994ca847f1c376e86735c54a6ee59 (patch)
tree414c46e79fef9ec56ca4424995b51b8369d5ffeb /src/field/mod.rs
parentc402a8923d2e89607a007f46ee4cde15714d746d (diff)
Use a result for the parser
Diffstat (limited to 'src/field/mod.rs')
-rw-r--r--src/field/mod.rs53
1 files changed, 36 insertions, 17 deletions
diff --git a/src/field/mod.rs b/src/field/mod.rs
index 277e7c4..a746ece 100644
--- a/src/field/mod.rs
+++ b/src/field/mod.rs
@@ -4,6 +4,13 @@ pub mod utils;
pub use id::ID;
use std::convert::TryInto;
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum Error {
+ #[error("Data could not be parsed as an integer.")]
+ InvalidInteger,
+}
/// Hotline defines 3 data types in the wire format:
/// 1) "integer" (16-bit or 32-bit, determined by magnitude)
@@ -33,9 +40,23 @@ pub struct Field {
/// - Some field IDs are definitely “integer” (e.g. user ID).
/// - Some are definitely “string” (e.g. user name).
/// - Others are “binary” (which might contain sub-structures).
-pub fn parse_field_value(id: ID, data: &[u8]) -> Value {
- use Value::*;
- use ID::*;
+#[must_use]
+pub fn parse_field_value(id: ID, data: &[u8]) -> Result<Value, Error> {
+ use Value::{Binary, Integer, Text};
+ use ID::{
+ AutomaticResponse, ChatID, ChatOptions, ChatSubject, CommunityBannerID, Data, ErrorText,
+ FileComment, FileCreateDate, FileCreatorString, FileModifyDate, FileName, FileNameWithInfo,
+ FileNewName, FileNewPath, FilePath, FileResumeData, FileSize, FileType, FileTypeString,
+ FileXferOptions, FolderItemCount, LegacyNewsCategoryListData, NewsArticle1stChildArticle,
+ NewsArticleData, NewsArticleDataFlavor, NewsArticleDate, NewsArticleFlags, NewsArticleID,
+ NewsArticleListData, NewsArticleNextArticle, NewsArticleParentArticle, NewsArticlePoster,
+ NewsArticlePrevArticle, NewsArticleRecurseDel, NewsArticleTitle, NewsCategoryGUID,
+ NewsCategoryListData, NewsCategoryName, NewsPath, NoServerAgreement, Options,
+ QuotingMessage, ReferenceNumber, ServerAgreement, ServerBanner, ServerBannerType,
+ ServerBannerUrl, ServerName, TransferSize, Unknown, UserAccess, UserAlias, UserFlags,
+ UserID, UserIconID, UserLogin, UserName, UserNameWithInfo, UserPassword, Version,
+ WaitingCount,
+ };
// By default, assume "binary"
// Then override to integer or string if the spec clearly says so.
@@ -71,20 +92,18 @@ pub fn parse_field_value(id: ID, data: &[u8]) -> Value {
let len = data.len();
if len == 2 {
- Integer(u16::from_be_bytes(data.try_into().unwrap()) as u32)
+ data.try_into()
+ .map(u16::from_be_bytes)
+ .map(u32::from)
+ .map(Integer)
+ .map_err(|_| Error::InvalidInteger)
} else if len == 4 {
- Integer(u32::from_be_bytes(data.try_into().unwrap()))
- } else if len == 0 {
- // no data => 0
- Integer(0)
+ data.try_into()
+ .map(u32::from_be_bytes)
+ .map(Integer)
+ .map_err(|_| Error::InvalidInteger)
} else {
- // fallback
- // interpret first 4 bytes, or everything as 32-bit
- let mut buf = [0u8; 4];
- for (i, b) in data.iter().enumerate().take(4) {
- buf[i] = *b;
- }
- Integer(u32::from_be_bytes(buf))
+ Err(Error::InvalidInteger)
}
}
@@ -106,7 +125,7 @@ pub fn parse_field_value(id: ID, data: &[u8]) -> Value {
| NewsArticleTitle
| NewsArticlePoster => {
let s = String::from_utf8_lossy(data).to_string();
- Text(s)
+ Ok(Text(s))
}
// Some are definitely “binary,” but might happen to contain text:
@@ -133,6 +152,6 @@ pub fn parse_field_value(id: ID, data: &[u8]) -> Value {
| NewsPath
| NewsArticleDate
| NewsArticleData
- | Unknown(_) => Binary(data.to_vec()),
+ | Unknown(_) => Ok(Binary(data.to_vec())),
}
}