use crate::codec::{Decode, DecodeError, Encode, EncodeError};
use crate::set::Payload;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum ErrorResponse {
UnexpectedMessage,
MalformedMessage,
UnsupportedVersionRange,
InvalidCredentials,
UnknownNfcUid,
NfcUidThrottled,
AudioUnavailable,
Custom(u8),
}
impl ErrorResponse {
pub fn code(&self) -> u8 {
match self {
Self::UnexpectedMessage => 0,
Self::MalformedMessage => 1,
Self::UnsupportedVersionRange => 2,
Self::InvalidCredentials => 3,
Self::UnknownNfcUid => 4,
Self::NfcUidThrottled => 5,
Self::AudioUnavailable => 6,
Self::Custom(code) => *code,
}
}
pub fn from_code(code: u8) -> Self {
match code {
0 => Self::UnexpectedMessage,
1 => Self::MalformedMessage,
2 => Self::UnsupportedVersionRange,
3 => Self::InvalidCredentials,
4 => Self::UnknownNfcUid,
5 => Self::NfcUidThrottled,
6 => Self::AudioUnavailable,
other => Self::Custom(other),
}
}
}
impl Payload for ErrorResponse {
const OPCODE: u8 = 0x00;
}
impl Encode for ErrorResponse {
fn encode(&self, out: &mut Vec<u8>) -> Result<(), EncodeError> {
out.push(self.code());
Ok(())
}
}
impl Decode for ErrorResponse {
fn decode(input: &mut &[u8]) -> Result<Self, DecodeError> {
Ok(Self::from_code(u8::decode(input)?))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::codec::{decode_payload, encode_payload};
#[test]
fn known_codes_round_trip() {
for code in 0..=6 {
let error = ErrorResponse::from_code(code);
assert!(!matches!(error, ErrorResponse::Custom(_)));
assert_eq!(error.code(), code);
assert_eq!(encode_payload(&error).unwrap(), [code]);
assert_eq!(decode_payload::<ErrorResponse>(&[code]).unwrap(), error);
}
}
#[test]
fn unknown_codes_decode_as_custom() {
assert_eq!(
decode_payload::<ErrorResponse>(&[0x07]).unwrap(),
ErrorResponse::Custom(0x07)
);
assert_eq!(
decode_payload::<ErrorResponse>(&[0x80]).unwrap(),
ErrorResponse::Custom(0x80)
);
}
#[test]
fn custom_with_dedicated_code_decodes_as_variant() {
let encoded = encode_payload(&ErrorResponse::Custom(3)).unwrap();
assert_eq!(encoded, [3]);
assert_eq!(
decode_payload::<ErrorResponse>(&encoded).unwrap(),
ErrorResponse::InvalidCredentials
);
}
}