Skip to main content

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}