do not use () as Err, clean up error handling
Some checks failed
Rust / build (pull_request) Failing after 1m15s

This commit is contained in:
Vinzenz Schroeter 2025-03-25 21:42:17 +01:00
parent 373d0efe55
commit fe1aa3ebd1
9 changed files with 67 additions and 73 deletions

View file

@ -33,8 +33,12 @@ impl From<CommandCode> for u16 {
} }
} }
#[derive(Debug, thiserror::Error, Eq, PartialEq)]
#[error("The command code {0} is not known.")]
pub struct InvalidCommandCodeError(pub u16);
impl TryFrom<u16> for CommandCode { impl TryFrom<u16> for CommandCode {
type Error = (); type Error = InvalidCommandCodeError;
/// Returns the enum value for the specified `u16` or `Error` if the code is unknown. /// Returns the enum value for the specified `u16` or `Error` if the code is unknown.
fn try_from(value: u16) -> Result<Self, Self::Error> { fn try_from(value: u16) -> Result<Self, Self::Error> {
@ -97,7 +101,7 @@ impl TryFrom<u16> for CommandCode {
value if value == CommandCode::Utf8Data as u16 => { value if value == CommandCode::Utf8Data as u16 => {
Ok(CommandCode::Utf8Data) Ok(CommandCode::Utf8Data)
} }
_ => Err(()), _ => Err(InvalidCommandCodeError(value)),
} }
} }
} }

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
command_code::CommandCode, command_code::{CommandCode, InvalidCommandCodeError},
commands::errors::{TryFromPacketError, TryIntoPacketError}, commands::errors::{TryFromPacketError, TryIntoPacketError},
compression::into_compressed, compression::into_compressed,
compression::into_decompressed, compression::into_decompressed,
@ -83,10 +83,7 @@ impl TryFrom<Packet> for BitmapCommand {
type Error = TryFromPacketError; type Error = TryFromPacketError;
fn try_from(packet: Packet) -> Result<Self, Self::Error> { fn try_from(packet: Packet) -> Result<Self, Self::Error> {
let code = CommandCode::try_from(packet.header.command_code).map_err( let code = CommandCode::try_from(packet.header.command_code)?;
|()| TryFromPacketError::InvalidCommand(packet.header.command_code),
)?;
match code { match code {
CommandCode::BitmapLinearWinUncompressed => { CommandCode::BitmapLinearWinUncompressed => {
Self::packet_into_bitmap_win( Self::packet_into_bitmap_win(
@ -111,9 +108,9 @@ impl TryFrom<Packet> for BitmapCommand {
Self::packet_into_bitmap_win(packet, CompressionCode::Zstd) Self::packet_into_bitmap_win(packet, CompressionCode::Zstd)
} }
_ => Err(TryFromPacketError::InvalidCommand( _ => {
packet.header.command_code, Err(InvalidCommandCodeError(packet.header.command_code).into())
)), }
} }
} }
} }
@ -182,9 +179,7 @@ mod tests {
..Default::default() ..Default::default()
} }
}), }),
Err(TryFromPacketError::InvalidCommand( Err(InvalidCommandCodeError(CommandCode::Brightness.into()).into())
CommandCode::Brightness.into()
))
); );
} }

View file

@ -1,7 +1,8 @@
use crate::{ use crate::{
command_code::CommandCode, commands::errors::TryFromPacketError, command_code::CommandCode, command_code::InvalidCommandCodeError,
compression::into_compressed, compression::into_decompressed, BitVec, commands::errors::TryFromPacketError, compression::into_compressed,
CompressionCode, Header, Offset, Packet, TryIntoPacketError, TypedCommand, compression::into_decompressed, BitVec, CompressionCode, Header, Offset,
Packet, TryIntoPacketError, TypedCommand,
}; };
/// Binary operations for use with the [`BitVecCommand`] command. /// Binary operations for use with the [`BitVecCommand`] command.
@ -86,29 +87,21 @@ impl TryFrom<Packet> for BitVecCommand {
}, },
payload, payload,
} = packet; } = packet;
let command_code = CommandCode::try_from(command_code) let command_code = CommandCode::try_from(command_code)?;
.map_err(|()| TryFromPacketError::InvalidCommand(command_code))?;
let operation = match command_code { let operation = match command_code {
CommandCode::BitmapLinear => BinaryOperation::Overwrite, CommandCode::BitmapLinear => BinaryOperation::Overwrite,
CommandCode::BitmapLinearAnd => BinaryOperation::And, CommandCode::BitmapLinearAnd => BinaryOperation::And,
CommandCode::BitmapLinearOr => BinaryOperation::Or, CommandCode::BitmapLinearOr => BinaryOperation::Or,
CommandCode::BitmapLinearXor => BinaryOperation::Xor, CommandCode::BitmapLinearXor => BinaryOperation::Xor,
_ => { _ => {
return Err(TryFromPacketError::InvalidCommand( return Err(InvalidCommandCodeError(command_code.into()).into());
command_code.into(),
))
} }
}; };
if reserved != 0 { if reserved != 0 {
return Err(TryFromPacketError::ExtraneousHeaderValues); return Err(TryFromPacketError::ExtraneousHeaderValues);
} }
let compression = match CompressionCode::try_from(sub) { let compression = CompressionCode::try_from(sub)?;
Err(()) => {
return Err(TryFromPacketError::InvalidCompressionCode(sub));
}
Ok(value) => value,
};
let payload = match into_decompressed(compression, payload) { let payload = match into_decompressed(compression, payload) {
None => return Err(TryFromPacketError::DecompressionFailed), None => return Err(TryFromPacketError::DecompressionFailed),
Some(value) => value, Some(value) => value,
@ -138,6 +131,7 @@ impl From<BitVecCommand> for TypedCommand {
mod tests { mod tests {
use super::*; use super::*;
use crate::commands::tests::{round_trip, TestImplementsCommand}; use crate::commands::tests::{round_trip, TestImplementsCommand};
use crate::compression_code::InvalidCompressionCodeError;
use crate::{commands, Bitmap, BitmapCommand, Origin}; use crate::{commands, Bitmap, BitmapCommand, Origin};
impl TestImplementsCommand for BitVecCommand {} impl TestImplementsCommand for BitVecCommand {}
@ -152,9 +146,7 @@ mod tests {
..Default::default() ..Default::default()
} }
}), }),
Err(TryFromPacketError::InvalidCommand( Err(InvalidCommandCodeError(CommandCode::Brightness.into()).into())
CommandCode::Brightness.into()
))
); );
} }
@ -285,7 +277,7 @@ mod tests {
}; };
assert_eq!( assert_eq!(
TypedCommand::try_from(p), TypedCommand::try_from(p),
Err(TryFromPacketError::InvalidCompressionCode(42)) Err(InvalidCompressionCodeError(42).into())
); );
} }

View file

@ -1,6 +1,7 @@
use crate::{ use crate::{
command_code::CommandCode, commands::check_command_code_only, command_code::CommandCode,
commands::errors::TryFromPacketError, Packet, TypedCommand, commands::{check_command_code_only, errors::TryFromPacketError},
Packet, TypedCommand,
}; };
use std::fmt::Debug; use std::fmt::Debug;
@ -43,6 +44,7 @@ impl From<ClearCommand> for TypedCommand {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::command_code::InvalidCommandCodeError;
use crate::commands::tests::TestImplementsCommand; use crate::commands::tests::TestImplementsCommand;
use crate::Header; use crate::Header;
@ -85,9 +87,7 @@ mod tests {
payload: vec![], payload: vec![],
}; };
assert_eq!( assert_eq!(
Err(TryFromPacketError::InvalidCommand( Err(InvalidCommandCodeError(CommandCode::HardReset.into()).into()),
CommandCode::HardReset.into()
)),
ClearCommand::try_from(p) ClearCommand::try_from(p)
); );
} }

View file

@ -1,12 +1,15 @@
use crate::LoadBitmapError; use crate::{
command_code::InvalidCommandCodeError,
compression_code::InvalidCompressionCodeError, LoadBitmapError,
};
use std::num::TryFromIntError; use std::num::TryFromIntError;
/// Err values for [`crate::TypedCommand::try_from`]. /// Err values for [`crate::TypedCommand::try_from`].
#[derive(Debug, PartialEq, thiserror::Error)] #[derive(Debug, PartialEq, thiserror::Error)]
pub enum TryFromPacketError { pub enum TryFromPacketError {
/// the contained command code does not correspond to a known command /// the contained command code does not correspond to a known command
#[error("The command code {0:?} does not correspond to a known command")] #[error(transparent)]
InvalidCommand(u16), InvalidCommand(#[from] InvalidCommandCodeError),
/// the expected payload size was n, but size m was found /// the expected payload size was n, but size m was found
#[error("the expected payload size was {0}, but size {1} was found")] #[error("the expected payload size was {0}, but size {1} was found")]
UnexpectedPayloadSize(usize, usize), UnexpectedPayloadSize(usize, usize),
@ -16,8 +19,8 @@ pub enum TryFromPacketError {
#[error("Header fields not needed for the command have been used")] #[error("Header fields not needed for the command have been used")]
ExtraneousHeaderValues, ExtraneousHeaderValues,
/// The contained compression code is not known. This could be of disabled features. /// The contained compression code is not known. This could be of disabled features.
#[error("The compression code {0:?} does not correspond to a known compression algorithm.")] #[error(transparent)]
InvalidCompressionCode(u16), InvalidCompression(#[from] InvalidCompressionCodeError),
/// Decompression of the payload failed. This can be caused by corrupted packets. /// Decompression of the payload failed. This can be caused by corrupted packets.
#[error("The decompression of the payload failed")] #[error("The decompression of the payload failed")]
DecompressionFailed, DecompressionFailed,

View file

@ -11,7 +11,7 @@ mod fade_out;
mod hard_reset; mod hard_reset;
mod typed; mod typed;
use crate::command_code::CommandCode; use crate::command_code::{CommandCode, InvalidCommandCodeError};
use crate::{Header, Packet}; use crate::{Header, Packet};
use std::fmt::Debug; use std::fmt::Debug;
@ -99,9 +99,7 @@ fn check_command_code_only(
payload, payload,
} = packet; } = packet;
if packet.header.command_code != u16::from(code) { if packet.header.command_code != u16::from(code) {
Some(TryFromPacketError::InvalidCommand( Some(InvalidCommandCodeError(packet.header.command_code).into())
packet.header.command_code,
))
} else if !payload.is_empty() { } else if !payload.is_empty() {
Some(TryFromPacketError::UnexpectedPayloadSize(0, payload.len())) Some(TryFromPacketError::UnexpectedPayloadSize(0, payload.len()))
} else if a != 0 || b != 0 || c != 0 || d != 0 { } else if a != 0 || b != 0 || c != 0 || d != 0 {
@ -114,11 +112,11 @@ fn check_command_code_only(
fn check_command_code( fn check_command_code(
actual: u16, actual: u16,
expected: CommandCode, expected: CommandCode,
) -> Result<(), TryFromPacketError> { ) -> Result<(), InvalidCommandCodeError> {
if actual == u16::from(expected) { if actual == u16::from(expected) {
Ok(()) Ok(())
} else { } else {
Err(TryFromPacketError::InvalidCommand(actual)) Err(InvalidCommandCodeError(actual))
} }
} }
@ -126,6 +124,10 @@ fn check_command_code(
mod tests { mod tests {
use crate::*; use crate::*;
#[allow(
unused,
reason = "false positive, used in submodules that check if structs impl Command"
)]
pub(crate) trait TestImplementsCommand: Command {} pub(crate) trait TestImplementsCommand: Command {}
pub(crate) fn round_trip(original: TypedCommand) { pub(crate) fn round_trip(original: TypedCommand) {

View file

@ -2,7 +2,7 @@ use crate::{
command_code::CommandCode, commands::errors::TryFromPacketError, command_code::CommandCode, commands::errors::TryFromPacketError,
BitVecCommand, BitmapCommand, BrightnessCommand, BrightnessGridCommand, BitVecCommand, BitmapCommand, BrightnessCommand, BrightnessGridCommand,
CharGridCommand, ClearCommand, Cp437GridCommand, FadeOutCommand, CharGridCommand, ClearCommand, Cp437GridCommand, FadeOutCommand,
HardResetCommand, Header, Packet, TryIntoPacketError, HardResetCommand, Packet, TryIntoPacketError,
}; };
/// This enum contains all commands provided by the library. /// This enum contains all commands provided by the library.
@ -31,18 +31,7 @@ impl TryFrom<Packet> for TypedCommand {
/// Try to interpret the [Packet] as one containing a [Command] /// Try to interpret the [Packet] as one containing a [Command]
fn try_from(packet: Packet) -> Result<Self, Self::Error> { fn try_from(packet: Packet) -> Result<Self, Self::Error> {
let Packet { Ok(match CommandCode::try_from(packet.header.command_code)? {
header: Header { command_code, .. },
..
} = packet;
let command_code = match CommandCode::try_from(command_code) {
Err(()) => {
return Err(TryFromPacketError::InvalidCommand(command_code));
}
Ok(value) => value,
};
Ok(match command_code {
CommandCode::Clear => { CommandCode::Clear => {
TypedCommand::Clear(crate::ClearCommand::try_from(packet)?) TypedCommand::Clear(crate::ClearCommand::try_from(packet)?)
} }
@ -119,9 +108,10 @@ impl TryFrom<TypedCommand> for Packet {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::commands::errors::TryFromPacketError; use crate::{
use crate::commands::tests::TestImplementsCommand; command_code::InvalidCommandCodeError,
use crate::{Header, Packet, TypedCommand}; commands::tests::TestImplementsCommand, Header, Packet, TypedCommand,
};
impl TestImplementsCommand for TypedCommand {} impl TestImplementsCommand for TypedCommand {}
@ -138,9 +128,6 @@ mod tests {
payload: vec![], payload: vec![],
}; };
let result = TypedCommand::try_from(p); let result = TypedCommand::try_from(p);
assert!(matches!( assert_eq!(result, Err(InvalidCommandCodeError(0xFF).into()));
result,
Err(TryFromPacketError::InvalidCommand(0xFF))
));
} }
} }

View file

@ -54,6 +54,10 @@ impl CompressionCode {
]; ];
} }
#[derive(Debug, thiserror::Error, Eq, PartialEq)]
#[error("The compression code {0} is not known.")]
pub struct InvalidCompressionCodeError(pub u16);
impl From<CompressionCode> for u16 { impl From<CompressionCode> for u16 {
fn from(value: CompressionCode) -> Self { fn from(value: CompressionCode) -> Self {
value as u16 value as u16
@ -61,7 +65,7 @@ impl From<CompressionCode> for u16 {
} }
impl TryFrom<u16> for CompressionCode { impl TryFrom<u16> for CompressionCode {
type Error = (); type Error = InvalidCompressionCodeError;
fn try_from(value: u16) -> Result<Self, Self::Error> { fn try_from(value: u16) -> Result<Self, Self::Error> {
match value { match value {
@ -84,7 +88,7 @@ impl TryFrom<u16> for CompressionCode {
value if value == CompressionCode::Zstd as u16 => { value if value == CompressionCode::Zstd as u16 => {
Ok(CompressionCode::Zstd) Ok(CompressionCode::Zstd)
} }
_ => Err(()), _ => Err(InvalidCompressionCodeError(value)),
} }
} }
} }

View file

@ -92,15 +92,19 @@ impl From<Packet> for Vec<u8> {
} }
} }
#[derive(Debug, thiserror::Error, Eq, PartialEq)]
#[error("The provided slice is smaller than the header size, so it cannot be read as a packet.")]
pub struct SliceSmallerThanHeader;
impl TryFrom<&[u8]> for Packet { impl TryFrom<&[u8]> for Packet {
type Error = (); type Error = SliceSmallerThanHeader;
/// Tries to interpret the bytes as a [Packet]. /// Tries to interpret the bytes as a [Packet].
/// ///
/// returns: `Error` if slice is not long enough to be a [Packet] /// returns: `Error` if slice is not long enough to be a [Packet]
fn try_from(value: &[u8]) -> Result<Self, Self::Error> { fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() < size_of::<Header>() { if value.len() < size_of::<Header>() {
return Err(()); return Err(SliceSmallerThanHeader);
} }
let header = { let header = {
@ -124,7 +128,7 @@ impl TryFrom<&[u8]> for Packet {
} }
impl TryFrom<Vec<u8>> for Packet { impl TryFrom<Vec<u8>> for Packet {
type Error = (); type Error = SliceSmallerThanHeader;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> { fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(value.as_slice()) Self::try_from(value.as_slice())
@ -203,6 +207,9 @@ mod tests {
#[test] #[test]
fn too_small() { fn too_small() {
let data = vec![0u8; 4]; let data = vec![0u8; 4];
assert_eq!(Packet::try_from(data.as_slice()), Err(())); assert_eq!(
Packet::try_from(data.as_slice()),
Err(SliceSmallerThanHeader)
);
} }
} }