[explorer, moves, core] Improve error handling in explorer
Implement thiserror::Error for a bunch of error types, and remove string errors from the implementation of the command handler in explorer. Clean up parsing of basic types all over the place. Update Cargo files to include thiserror and anyhow.
This commit is contained in:
parent
72eeba84ba
commit
9010f1e9c2
12 changed files with 331 additions and 226 deletions
137
core/src/shapes.rs
Normal file
137
core/src/shapes.rs
Normal file
|
@ -0,0 +1,137 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use std::{array, slice};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum Shape {
|
||||
Pawn = 0,
|
||||
Knight = 1,
|
||||
Bishop = 2,
|
||||
Rook = 3,
|
||||
Queen = 4,
|
||||
King = 5,
|
||||
}
|
||||
|
||||
impl Shape {
|
||||
/// Number of piece shapes
|
||||
pub const NUM: usize = 6;
|
||||
|
||||
/// A slice of all piece shapes
|
||||
pub const ALL: [Shape; Self::NUM] = [
|
||||
Shape::Pawn,
|
||||
Shape::Knight,
|
||||
Shape::Bishop,
|
||||
Shape::Rook,
|
||||
Shape::Queen,
|
||||
Shape::King,
|
||||
];
|
||||
|
||||
pub fn iter() -> slice::Iter<'static, Self> {
|
||||
Shape::ALL.iter()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn into_iter() -> array::IntoIter<Self, { Self::NUM }> {
|
||||
Shape::ALL.into_iter()
|
||||
}
|
||||
|
||||
/// An iterator over the shapes that a pawn can promote to
|
||||
pub fn promotable() -> slice::Iter<'static, Shape> {
|
||||
const PROMOTABLE_SHAPES: [Shape; 4] =
|
||||
[Shape::Queen, Shape::Rook, Shape::Bishop, Shape::Knight];
|
||||
|
||||
PROMOTABLE_SHAPES.iter()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn to_ascii(self) -> char {
|
||||
match self {
|
||||
Shape::Pawn => 'P',
|
||||
Shape::Knight => 'N',
|
||||
Shape::Bishop => 'B',
|
||||
Shape::Rook => 'R',
|
||||
Shape::Queen => 'Q',
|
||||
Shape::King => 'K',
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn name(self) -> &'static str {
|
||||
match self {
|
||||
Shape::Pawn => "pawn",
|
||||
Shape::Knight => "knight",
|
||||
Shape::Bishop => "bishop",
|
||||
Shape::Rook => "rook",
|
||||
Shape::Queen => "queen",
|
||||
Shape::King => "king",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
|
||||
#[error("no matching piece shape for character '{0:?}'")]
|
||||
pub struct ShapeFromCharError(char);
|
||||
|
||||
impl TryFrom<char> for Shape {
|
||||
type Error = ShapeFromCharError;
|
||||
|
||||
fn try_from(value: char) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
'P' | 'p' => Ok(Shape::Pawn),
|
||||
'N' | 'n' => Ok(Shape::Knight),
|
||||
'B' | 'b' => Ok(Shape::Bishop),
|
||||
'R' | 'r' => Ok(Shape::Rook),
|
||||
'Q' | 'q' => Ok(Shape::Queen),
|
||||
'K' | 'k' => Ok(Shape::King),
|
||||
_ => Err(ShapeFromCharError(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
|
||||
#[error("no matching piece shape for string")]
|
||||
pub struct ShapeFromStrError;
|
||||
|
||||
impl TryFrom<&str> for Shape {
|
||||
type Error = ShapeFromStrError;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
match value.to_lowercase().as_str() {
|
||||
"p" | "pawn" => Ok(Shape::Pawn),
|
||||
"n" | "knight" => Ok(Shape::Knight),
|
||||
"b" | "bishop" => Ok(Shape::Bishop),
|
||||
"r" | "rook" => Ok(Shape::Rook),
|
||||
"q" | "queen" => Ok(Shape::Queen),
|
||||
"k" | "king" => Ok(Shape::King),
|
||||
_ => Err(ShapeFromStrError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for Shape {
|
||||
type Err = ShapeFromStrError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::try_from(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Shape> for char {
|
||||
fn from(shape: &Shape) -> char {
|
||||
char::from(*shape)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Shape> for char {
|
||||
fn from(shape: Shape) -> char {
|
||||
shape.to_ascii()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Shape {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let self_char: char = self.into();
|
||||
write!(f, "{self_char}")
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue