[core] Move the contents of board::square to core::coordinates
Export Square, Rank, and File from the core crate.
This commit is contained in:
		
							parent
							
								
									7e08a9adc4
								
							
						
					
					
						commit
						406631b617
					
				
					 3 changed files with 212 additions and 153 deletions
				
			
		| 
						 | 
					@ -12,7 +12,6 @@ mod move_generator;
 | 
				
			||||||
pub mod piece;
 | 
					pub mod piece;
 | 
				
			||||||
mod position;
 | 
					mod position;
 | 
				
			||||||
mod sight;
 | 
					mod sight;
 | 
				
			||||||
mod square;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use piece::{Color, Piece};
 | 
					pub use piece::{Color, Piece};
 | 
				
			||||||
pub use position::{MoveBuilder as MakeMoveBuilder, Position, PositionBuilder};
 | 
					pub use position::{MoveBuilder as MakeMoveBuilder, Position, PositionBuilder};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,10 @@
 | 
				
			||||||
// Eryn Wells <eryn@erynwells.me>
 | 
					// Eryn Wells <eryn@erynwells.me>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::Color;
 | 
					use std::fmt;
 | 
				
			||||||
use std::{fmt, str::FromStr};
 | 
					use std::str::FromStr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Debug, Eq, PartialEq)]
 | 
				
			||||||
 | 
					#[repr(u8)]
 | 
				
			||||||
pub enum Direction {
 | 
					pub enum Direction {
 | 
				
			||||||
    North,
 | 
					    North,
 | 
				
			||||||
    NorthWest,
 | 
					    NorthWest,
 | 
				
			||||||
| 
						 | 
					@ -14,14 +16,24 @@ pub enum Direction {
 | 
				
			||||||
    NorthEast,
 | 
					    NorthEast,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					impl Direction {
 | 
				
			||||||
pub struct ParseFileError;
 | 
					    pub fn to_offset(&self) -> i8 {
 | 
				
			||||||
 | 
					        const OFFSETS: [i8; 8] = [8, 7, -1, -9, -8, -7, 1, 9];
 | 
				
			||||||
 | 
					        OFFSETS[*self as usize]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					macro_rules! try_from_integer {
 | 
				
			||||||
pub struct ParseSquareError;
 | 
					    ($type:ident, $int_type:ident) => {
 | 
				
			||||||
 | 
					        impl TryFrom<$int_type> for $type {
 | 
				
			||||||
 | 
					            type Error = ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					            fn try_from(value: $int_type) -> Result<Self, Self::Error> {
 | 
				
			||||||
pub struct SquareOutOfBoundsError;
 | 
					                Square::try_from(value as u8)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro_rules! coordinate_enum {
 | 
					macro_rules! coordinate_enum {
 | 
				
			||||||
    ($name: ident, $($variant:ident),*) => {
 | 
					    ($name: ident, $($variant:ident),*) => {
 | 
				
			||||||
| 
						 | 
					@ -34,43 +46,116 @@ macro_rules! coordinate_enum {
 | 
				
			||||||
        impl $name {
 | 
					        impl $name {
 | 
				
			||||||
            pub const NUM: usize = [$(Self::$variant), *].len();
 | 
					            pub const NUM: usize = [$(Self::$variant), *].len();
 | 
				
			||||||
            pub const ALL: [Self; Self::NUM] = [$(Self::$variant), *];
 | 
					            pub const ALL: [Self; Self::NUM] = [$(Self::$variant), *];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #[inline]
 | 
					        impl TryFrom<u8> for $name {
 | 
				
			||||||
            pub(crate) fn from_index(index: usize) -> Self {
 | 
					            type Error = ();
 | 
				
			||||||
                assert!(
 | 
					
 | 
				
			||||||
                    index < Self::NUM,
 | 
					            fn try_from(value: u8) -> Result<Self, Self::Error> {
 | 
				
			||||||
                    "Index {} out of bounds for {}.",
 | 
					                let value_usize = value as usize;
 | 
				
			||||||
                    index,
 | 
					                if value_usize < Self::NUM {
 | 
				
			||||||
                    stringify!($name)
 | 
					                    Ok($name::ALL[value_usize])
 | 
				
			||||||
                );
 | 
					                } else {
 | 
				
			||||||
                Self::try_index(index).unwrap()
 | 
					                    Err(())
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try_from_integer!($name, u16);
 | 
				
			||||||
 | 
					        try_from_integer!($name, u32);
 | 
				
			||||||
 | 
					        try_from_integer!($name, u64);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! range_bound_struct {
 | 
				
			||||||
 | 
					    ($vis:vis, $type:ident, $repr:ty, $max:expr) => {
 | 
				
			||||||
 | 
					        #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
 | 
				
			||||||
 | 
					        $vis struct $type($repr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #[allow(dead_code)]
 | 
				
			||||||
 | 
					        impl $type {
 | 
				
			||||||
 | 
					            $vis const FIRST: $type = $type(0);
 | 
				
			||||||
 | 
					            $vis const LAST: $type = $type($max - 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl $type {
 | 
				
			||||||
 | 
					            $vis fn new(x: $repr) -> Option<Self> {
 | 
				
			||||||
 | 
					                if x < $max {
 | 
				
			||||||
 | 
					                    Some(Self(x))
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pub fn try_index(index: usize) -> Option<Self> {
 | 
					            $vis unsafe fn new_unchecked(x: $repr) -> Self {
 | 
				
			||||||
                $(
 | 
					                Self(x)
 | 
				
			||||||
                    #[allow(non_upper_case_globals)]
 | 
					            }
 | 
				
			||||||
                    const $variant: usize = $name::$variant as usize;
 | 
					        }
 | 
				
			||||||
                )*
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                #[allow(non_upper_case_globals)]
 | 
					        impl Into<$repr> for $type {
 | 
				
			||||||
                match index {
 | 
					            fn into(self) -> $repr {
 | 
				
			||||||
                    $($variant => Some($name::$variant),)*
 | 
					                self.0
 | 
				
			||||||
                    _ => None,
 | 
					            }
 | 
				
			||||||
                }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl TryFrom<$repr> for $type {
 | 
				
			||||||
 | 
					            type Error = ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fn try_from(value: $repr) -> Result<Self, Self::Error> {
 | 
				
			||||||
 | 
					                Self::new(value).ok_or(())
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[rustfmt::skip]
 | 
					range_bound_struct!(pub, File, u8, 8);
 | 
				
			||||||
coordinate_enum!(Rank,
 | 
					 | 
				
			||||||
    One, Two, Three, Four, Five, Six, Seven, Eight
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[rustfmt::skip]
 | 
					impl File {
 | 
				
			||||||
coordinate_enum!(File,
 | 
					    pub const A: File = File(0);
 | 
				
			||||||
    A, B, C, D, E, F, G, H
 | 
					    pub const B: File = File(1);
 | 
				
			||||||
);
 | 
					    pub const C: File = File(2);
 | 
				
			||||||
 | 
					    pub const D: File = File(3);
 | 
				
			||||||
 | 
					    pub const E: File = File(4);
 | 
				
			||||||
 | 
					    pub const F: File = File(5);
 | 
				
			||||||
 | 
					    pub const G: File = File(6);
 | 
				
			||||||
 | 
					    pub const H: File = File(7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub const ALL: [File; 8] = [
 | 
				
			||||||
 | 
					        File::A,
 | 
				
			||||||
 | 
					        File::B,
 | 
				
			||||||
 | 
					        File::C,
 | 
				
			||||||
 | 
					        File::D,
 | 
				
			||||||
 | 
					        File::E,
 | 
				
			||||||
 | 
					        File::F,
 | 
				
			||||||
 | 
					        File::G,
 | 
				
			||||||
 | 
					        File::H,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					range_bound_struct!(pub, Rank, u8, 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(dead_code)]
 | 
				
			||||||
 | 
					impl Rank {
 | 
				
			||||||
 | 
					    pub const ONE: Rank = Rank(0);
 | 
				
			||||||
 | 
					    pub const TWO: Rank = Rank(1);
 | 
				
			||||||
 | 
					    pub const THREE: Rank = Rank(2);
 | 
				
			||||||
 | 
					    pub const FOUR: Rank = Rank(3);
 | 
				
			||||||
 | 
					    pub const FIVE: Rank = Rank(4);
 | 
				
			||||||
 | 
					    pub const SIX: Rank = Rank(5);
 | 
				
			||||||
 | 
					    pub const SEVEN: Rank = Rank(6);
 | 
				
			||||||
 | 
					    pub const EIGHT: Rank = Rank(7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub const ALL: [Rank; 8] = [
 | 
				
			||||||
 | 
					        Rank::ONE,
 | 
				
			||||||
 | 
					        Rank::TWO,
 | 
				
			||||||
 | 
					        Rank::THREE,
 | 
				
			||||||
 | 
					        Rank::FOUR,
 | 
				
			||||||
 | 
					        Rank::FIVE,
 | 
				
			||||||
 | 
					        Rank::SIX,
 | 
				
			||||||
 | 
					        Rank::SEVEN,
 | 
				
			||||||
 | 
					        Rank::EIGHT,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[rustfmt::skip]
 | 
					#[rustfmt::skip]
 | 
				
			||||||
coordinate_enum!(Square,
 | 
					coordinate_enum!(Square,
 | 
				
			||||||
| 
						 | 
					@ -84,138 +169,87 @@ coordinate_enum!(Square,
 | 
				
			||||||
    A8, B8, C8, D8, E8, F8, G8, H8
 | 
					    A8, B8, C8, D8, E8, F8, G8, H8
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Into<char> for File {
 | 
					 | 
				
			||||||
    fn into(self) -> char {
 | 
					 | 
				
			||||||
        ('a' as u8 + self as u8) as char
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl TryFrom<char> for File {
 | 
					 | 
				
			||||||
    type Error = ParseFileError;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn try_from(value: char) -> Result<Self, Self::Error> {
 | 
					 | 
				
			||||||
        let lowercase_value = value.to_ascii_lowercase();
 | 
					 | 
				
			||||||
        for file in File::ALL.iter() {
 | 
					 | 
				
			||||||
            if lowercase_value == (*file).into() {
 | 
					 | 
				
			||||||
                return Ok(*file);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Err(ParseFileError)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl fmt::Display for File {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        write!(f, "{}", Into::<char>::into(*self).to_uppercase())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Into<char> for Rank {
 | 
					 | 
				
			||||||
    fn into(self) -> char {
 | 
					 | 
				
			||||||
        ('1' as u8 + self as u8) as char
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl TryFrom<char> for Rank {
 | 
					 | 
				
			||||||
    type Error = ParseFileError;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn try_from(value: char) -> Result<Self, Self::Error> {
 | 
					 | 
				
			||||||
        let lowercase_value = value.to_ascii_lowercase();
 | 
					 | 
				
			||||||
        for rank in Self::ALL.iter().cloned() {
 | 
					 | 
				
			||||||
            if lowercase_value == rank.into() {
 | 
					 | 
				
			||||||
                return Ok(rank);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Err(ParseFileError)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl fmt::Display for Rank {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        write!(f, "{}", Into::<char>::into(*self))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Square {
 | 
					impl Square {
 | 
				
			||||||
 | 
					    pub unsafe fn from_index(x: u8) -> Square {
 | 
				
			||||||
 | 
					        Self::try_from(x).unwrap_unchecked()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    pub fn from_file_rank(file: File, rank: Rank) -> Square {
 | 
					    pub fn from_file_rank(file: File, rank: Rank) -> Square {
 | 
				
			||||||
        Self::from_index((rank as usize) << 3 | file as usize)
 | 
					        let file_int: u8 = file.into();
 | 
				
			||||||
    }
 | 
					        let rank_int: u8 = rank.into();
 | 
				
			||||||
 | 
					        unsafe { Self::from_index(rank_int << 3 | file_int) }
 | 
				
			||||||
    #[inline]
 | 
					 | 
				
			||||||
    pub fn file(self) -> File {
 | 
					 | 
				
			||||||
        File::from_index(self as usize & 0b000111)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[inline]
 | 
					 | 
				
			||||||
    pub fn rank(self) -> Rank {
 | 
					 | 
				
			||||||
        Rank::from_index(self as usize >> 3)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Square {
 | 
					 | 
				
			||||||
    const KING_STARTING_SQUARES: [Square; 2] = [Square::E1, Square::E8];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn king_starting_square(color: Color) -> Square {
 | 
					 | 
				
			||||||
        Square::KING_STARTING_SQUARES[color as usize]
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn from_algebraic_str(s: &str) -> Result<Square, ParseSquareError> {
 | 
					    pub fn from_algebraic_str(s: &str) -> Result<Square, ParseSquareError> {
 | 
				
			||||||
        s.parse()
 | 
					        s.parse()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    pub fn file(self) -> File {
 | 
				
			||||||
 | 
					        unsafe { File::new_unchecked((self as u8) & 0b000111) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    pub fn rank(self) -> Rank {
 | 
				
			||||||
 | 
					        unsafe { Rank::new_unchecked((self as u8) >> 3) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn neighbor(self, direction: Direction) -> Option<Square> {
 | 
					    pub fn neighbor(self, direction: Direction) -> Option<Square> {
 | 
				
			||||||
 | 
					        let index: u8 = self as u8;
 | 
				
			||||||
 | 
					        let dir: i8 = direction.to_offset();
 | 
				
			||||||
        match direction {
 | 
					        match direction {
 | 
				
			||||||
            Direction::North => Square::try_index(self as usize + 8),
 | 
					            Direction::North => Square::try_from(index.wrapping_add_signed(dir)).ok(),
 | 
				
			||||||
            Direction::NorthWest => {
 | 
					            Direction::NorthWest => {
 | 
				
			||||||
                if self.rank() != Rank::Eight {
 | 
					                if self.rank() != Rank::EIGHT {
 | 
				
			||||||
                    Square::try_index(self as usize + 7)
 | 
					                    Square::try_from(index.wrapping_add_signed(dir)).ok()
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    None
 | 
					                    None
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Direction::West => {
 | 
					            Direction::West => {
 | 
				
			||||||
                if self.file() != File::A {
 | 
					                if self.file() != File::A {
 | 
				
			||||||
                    Square::try_index(self as usize - 1)
 | 
					                    Square::try_from(index.wrapping_add_signed(dir)).ok()
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    None
 | 
					                    None
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Direction::SouthWest => {
 | 
					            Direction::SouthWest => {
 | 
				
			||||||
                if self.rank() != Rank::One {
 | 
					                if self.rank() != Rank::ONE {
 | 
				
			||||||
                    Square::try_index(self as usize - 9)
 | 
					                    Square::try_from(index.wrapping_add_signed(dir)).ok()
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    None
 | 
					                    None
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Direction::South => {
 | 
					            Direction::South => {
 | 
				
			||||||
                if self.rank() != Rank::One {
 | 
					                if self.rank() != Rank::ONE {
 | 
				
			||||||
                    Square::try_index(self as usize - 8)
 | 
					                    Square::try_from(index.wrapping_add_signed(dir)).ok()
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    None
 | 
					                    None
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Direction::SouthEast => {
 | 
					            Direction::SouthEast => {
 | 
				
			||||||
                if self.rank() != Rank::One {
 | 
					                if self.rank() != Rank::ONE {
 | 
				
			||||||
                    Square::try_index(self as usize - 7)
 | 
					                    Square::try_from(index.wrapping_add_signed(dir)).ok()
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    None
 | 
					                    None
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Direction::East => {
 | 
					            Direction::East => {
 | 
				
			||||||
                if self.file() != File::H {
 | 
					                if self.file() != File::H {
 | 
				
			||||||
                    Square::try_index(self as usize + 1)
 | 
					                    Square::try_from(index.wrapping_add_signed(dir)).ok()
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    None
 | 
					                    None
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Direction::NorthEast => Square::try_index(self as usize + 9),
 | 
					            Direction::NorthEast => Square::try_from(index.wrapping_add_signed(dir)).ok(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Debug, Eq, PartialEq)]
 | 
				
			||||||
 | 
					pub struct ParseSquareError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl FromStr for Square {
 | 
					impl FromStr for Square {
 | 
				
			||||||
    type Err = ParseSquareError;
 | 
					    type Err = ParseSquareError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -240,31 +274,54 @@ impl FromStr for Square {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro_rules! try_from_integer {
 | 
					impl fmt::Display for File {
 | 
				
			||||||
    ($int_type:ident) => {
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
        impl TryFrom<$int_type> for Square {
 | 
					        write!(f, "{}", Into::<char>::into(*self))
 | 
				
			||||||
            type Error = SquareOutOfBoundsError;
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            fn try_from(value: $int_type) -> Result<Self, Self::Error> {
 | 
					 | 
				
			||||||
                Square::try_index(value as usize).ok_or(SquareOutOfBoundsError)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
try_from_integer!(u8);
 | 
					impl fmt::Display for Rank {
 | 
				
			||||||
try_from_integer!(u16);
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
try_from_integer!(u32);
 | 
					        write!(f, "{}", Into::<char>::into(*self))
 | 
				
			||||||
try_from_integer!(u64);
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl fmt::Display for Square {
 | 
					impl fmt::Display for Square {
 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
        write!(
 | 
					        self.file().fmt(f)?;
 | 
				
			||||||
            f,
 | 
					        self.rank().fmt(f)?;
 | 
				
			||||||
            "{}{}",
 | 
					        Ok(())
 | 
				
			||||||
            ('a' as u8 + self.file() as u8) as char,
 | 
					    }
 | 
				
			||||||
            self.rank() as usize + 1
 | 
					}
 | 
				
			||||||
        )
 | 
					
 | 
				
			||||||
 | 
					impl Into<char> for File {
 | 
				
			||||||
 | 
					    fn into(self) -> char {
 | 
				
			||||||
 | 
					        let value: u8 = self.into();
 | 
				
			||||||
 | 
					        (value + 'a' as u8) as char
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Into<char> for Rank {
 | 
				
			||||||
 | 
					    fn into(self) -> char {
 | 
				
			||||||
 | 
					        let value: u8 = self.into();
 | 
				
			||||||
 | 
					        (value + '1' as u8) as char
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl TryFrom<char> for File {
 | 
				
			||||||
 | 
					    type Error = ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn try_from(value: char) -> Result<Self, Self::Error> {
 | 
				
			||||||
 | 
					        File::try_from(value.to_ascii_lowercase() as u8 - 'a' as u8)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl TryFrom<char> for Rank {
 | 
				
			||||||
 | 
					    type Error = ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn try_from(value: char) -> Result<Self, Self::Error> {
 | 
				
			||||||
 | 
					        let result = (value as u8).checked_sub('1' as u8).ok_or(())?;
 | 
				
			||||||
 | 
					        Self::try_from(result)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -275,16 +332,16 @@ mod tests {
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn good_algebraic_input() {
 | 
					    fn good_algebraic_input() {
 | 
				
			||||||
        let sq = Square::from_algebraic_str("a4").expect("Failed to parse 'a4' square");
 | 
					        let sq = Square::from_algebraic_str("a4").expect("Failed to parse 'a4' square");
 | 
				
			||||||
        assert_eq!(sq.file(), File::A);
 | 
					        assert_eq!(sq.file(), File(0));
 | 
				
			||||||
        assert_eq!(sq.rank(), Rank::Four);
 | 
					        assert_eq!(sq.rank(), Rank(3));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let sq = Square::from_algebraic_str("B8").expect("Failed to parse 'B8' square");
 | 
					        let sq = Square::from_algebraic_str("B8").expect("Failed to parse 'B8' square");
 | 
				
			||||||
        assert_eq!(sq.file(), File::B);
 | 
					        assert_eq!(sq.file(), File(1));
 | 
				
			||||||
        assert_eq!(sq.rank(), Rank::Eight);
 | 
					        assert_eq!(sq.rank(), Rank(7));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let sq = Square::from_algebraic_str("e4").expect("Failed to parse 'B8' square");
 | 
					        let sq = Square::from_algebraic_str("e4").expect("Failed to parse 'B8' square");
 | 
				
			||||||
        assert_eq!(sq.file(), File::E);
 | 
					        assert_eq!(sq.file(), File(4));
 | 
				
			||||||
        assert_eq!(sq.rank(), Rank::Four);
 | 
					        assert_eq!(sq.rank(), Rank(3));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
| 
						 | 
					@ -299,13 +356,13 @@ mod tests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn from_index() {
 | 
					    fn from_index() {
 | 
				
			||||||
        let sq = Square::try_index(4).expect("Unable to get Square from index");
 | 
					        let sq = Square::try_from(4u32).expect("Unable to get Square from index");
 | 
				
			||||||
        assert_eq!(sq.file(), File::E);
 | 
					        assert_eq!(sq.file(), File(4));
 | 
				
			||||||
        assert_eq!(sq.rank(), Rank::One);
 | 
					        assert_eq!(sq.rank(), Rank(0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let sq = Square::try_index(28).expect("Unable to get Square from index");
 | 
					        let sq = Square::try_from(28u32).expect("Unable to get Square from index");
 | 
				
			||||||
        assert_eq!(sq.file(), File::E);
 | 
					        assert_eq!(sq.file(), File(4));
 | 
				
			||||||
        assert_eq!(sq.rank(), Rank::Four);
 | 
					        assert_eq!(sq.rank(), Rank(3));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					mod coordinates;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub use coordinates::{Direction, File, Rank, Square};
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue