chessnut_move/protocol/errors.rs
1// Copyright 2026 Daymon Littrell-Reyes
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Structured validation errors returned by notification decoders.
16
17use thiserror::Error;
18
19#[cfg(doc)]
20use crate::protocol;
21use crate::protocol::Square;
22
23/// Reports that a notification does not contain its complete required payload.
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
25#[error("notification is too short: expected at least {expected} bytes, got {actual}")]
26pub struct NotificationTooShortError {
27 /// Minimum number of bytes required for this notification type.
28 pub expected: usize,
29
30 /// Number of bytes present in the received notification.
31 pub actual: usize,
32}
33
34/// Reports an invalid field in a [board battery] response.
35///
36/// [board battery]: protocol::Command::read_battery_level
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
38pub enum BatteryStatusError {
39 /// The charging flag was neither zero nor one.
40 ///
41 /// The standard Move board's response for battery status has a third byte which represents the
42 /// state of charging; `0` for not charging, and `1` for charging.
43 #[error("invalid charging flag {0:#04x}: expected 0 or 1")]
44 InvalidChargingFlag(u8),
45
46 /// The reported board battery percentage exceeded 100.
47 #[error("invalid battery percentage {0}: expected a value from 0 through 100")]
48 InvalidBatteryPercentage(u8),
49}
50
51/// Reports an invalid field in a [piece status] response.
52///
53/// [piece status]: protocol::Command::read_piece_status
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
55pub enum PieceStatusError {
56 /// A piece record contained an unknown identity code.
57 #[error("invalid tracked-piece identity {value:#04x} at index {index}")]
58 InvalidTrackedPiece {
59 /// Zero-based record index in the tracked-piece response.
60 index: usize,
61
62 /// Unrecognized identity byte.
63 value: u8,
64 },
65
66 /// A battery value was neither a percentage nor the unavailable sentinel.
67 #[error(
68 "invalid tracked-piece battery percentage {value} at index {index}: expected 0 through 100 or 0xff for unavailable"
69 )]
70 InvalidTrackedPieceBattery {
71 /// Zero-based record index in the tracked-piece response.
72 index: usize,
73
74 /// Invalid battery byte.
75 value: u8,
76 },
77}
78
79/// Reports why a command-response notification could not be decoded.
80#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
81pub enum DecodeResponseNotificationError {
82 /// The response ended before its required fields were available.
83 #[error(transparent)]
84 NotificationTooShort(#[from] NotificationTooShortError),
85
86 /// A tracked-piece response contained an invalid field.
87 #[error(transparent)]
88 PieceStatus(#[from] PieceStatusError),
89
90 /// A board battery response contained an invalid field.
91 #[error(transparent)]
92 BatteryStatus(#[from] BatteryStatusError),
93
94 /// The response type byte is not supported by this crate.
95 #[error("unexpected notification type {0:#04x}")]
96 UnexpectedNotification(u8),
97
98 /// A fixed response-header byte did not match the protocol.
99 #[error(
100 "invalid notification header byte at offset {offset}: expected {expected:#04x}, got {actual:#04x}"
101 )]
102 InvalidNotificationHeader {
103 /// Zero-based byte offset of the invalid header field.
104 offset: usize,
105
106 /// Header byte required by the protocol.
107 expected: u8,
108
109 /// Header byte found in the notification.
110 actual: u8,
111 },
112}
113
114/// Reports why a [position notification] could not be decoded.
115///
116/// [position notification]: protocol::BoardEvent::PositionChanged
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
118pub enum DecodePositionNotificationError {
119 /// The notification ended before all 64 squares were available.
120 #[error(transparent)]
121 NotificationTooShort(#[from] NotificationTooShortError),
122
123 /// A square contained an unknown four-bit piece code.
124 #[error("invalid piece value {value:#04x} at square {square}")]
125 InvalidPiece {
126 /// Square containing the invalid value.
127 square: Square,
128
129 /// Unrecognized four-bit piece code.
130 value: u8,
131 },
132}