Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce binary size #645

Merged
merged 1 commit into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,11 @@ criterion-macro = { version = "0.4.0", default-features = false }
proptest = { version = "1.5.0", default-features = false, features = ["std"] }
test-strategy = { version = "0.4.0", default-features = false }

[profile.release.package.ruzstd]
opt-level = 's'

[profile.release]
codegen-units = 1
lto = true
panic = "abort"
strip = "symbols"
lto = true
strip = true

[profile.dev]
opt-level = 3
Expand Down
37 changes: 11 additions & 26 deletions bin/main.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,21 @@
use futures::executor::{block_on, block_on_stream};
use futures::{channel::mpsc, prelude::*};
use futures::executor::block_on;
use futures::{channel::mpsc::unbounded, sink::unfold};
use lib::uci::Uci;
use std::io::{prelude::*, stdin, stdout, LineWriter};
use std::thread;
use std::io::{prelude::*, stdin, stdout};
use std::{future::ready, thread};

fn main() {
let (mut tx, input) = mpsc::channel(32);
let (output, rx) = mpsc::channel(32);
let (tx, rx) = unbounded();

Check warning on line 8 in bin/main.rs

View check run for this annotation

Codecov / codecov/patch

bin/main.rs#L8

Added line #L8 was not covered by tests

thread::spawn(move || {
for item in stdin().lock().lines() {
match item {
Err(error) => return eprint!("{error}"),
Ok(line) => {
if let Err(error) = block_on(tx.send(line)) {
if error.is_disconnected() {
break;
}
}
}
for line in stdin().lock().lines() {
if tx.unbounded_send(line.unwrap()).is_err() {
break;

Check warning on line 13 in bin/main.rs

View check run for this annotation

Codecov / codecov/patch

bin/main.rs#L11-L13

Added lines #L11 - L13 were not covered by tests
}
}
});

thread::spawn(move || {
let mut stdout = LineWriter::new(stdout().lock());
for line in block_on_stream(rx) {
if let Err(error) = writeln!(stdout, "{line}") {
return eprint!("{error}");
}
}
});

block_on(Uci::new(input, output).run()).ok();
let mut stdout = stdout().lock();
let output = unfold((), |_, line: String| ready(writeln!(stdout, "{line}")));
block_on(Uci::new(rx, output).run()).unwrap();

Check warning on line 20 in bin/main.rs

View check run for this annotation

Codecov / codecov/patch

bin/main.rs#L18-L20

Added lines #L18 - L20 were not covered by tests
}
6 changes: 3 additions & 3 deletions lib/chess/bitboard.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::chess::{File, Perspective, Rank, Square};
use crate::util::{Assume, Integer};
use derive_more::{Debug, *};
use std::fmt::{self, Write};
use std::fmt::{self, Formatter, Write};
use std::{cell::SyncUnsafeCell, mem::MaybeUninit};

/// A set of squares on a chess board.
Expand All @@ -26,9 +26,9 @@ use std::{cell::SyncUnsafeCell, mem::MaybeUninit};
#[repr(transparent)]
pub struct Bitboard(u64);

impl fmt::Debug for Bitboard {
impl Debug for Bitboard {
#[coverage(off)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_char('\n')?;
for rank in Rank::iter().rev() {
for file in File::iter() {
Expand Down
37 changes: 22 additions & 15 deletions lib/chess/board.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::{chess::*, util::Integer};
use arrayvec::ArrayString;
use crate::chess::*;
use crate::util::{Assume, Integer};
use derive_more::{Debug, Display, Error};
use std::fmt::{self, Write};
use std::{ops::Index, str::FromStr};
use std::fmt::{self, Formatter, Write};
use std::str::{self, FromStr};
use std::{io::Write as _, ops::Index};

/// The chess board.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
Expand Down Expand Up @@ -163,26 +164,31 @@ impl Index<Square> for Board {
}

impl Display for Board {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut skip = 0;
for sq in Square::iter().map(|sq| sq.flip()) {
let mut buffer = ArrayString::<2>::new();
let mut buffer = [b'\0'; 2];

match self[sq] {
None => skip += 1,
Some(p) => write!(buffer, "{}", p)?,
if sq.file() == File::H {
buffer[0] = if sq.rank() == Rank::First { b' ' } else { b'/' };
}

if sq.file() == File::H {
buffer.push(if sq.rank() == Rank::First { ' ' } else { '/' });
match self[sq] {
None => skip += 1,
Some(p) => {
buffer[1] = buffer[0];
write!(&mut buffer[..1], "{p}").assume()
}
}

if !buffer.is_empty() && skip > 0 {
write!(f, "{}", skip)?;
if skip > 0 && buffer != [b'\0'; 2] {
write!(f, "{skip}")?;
skip = 0;
}

f.write_str(&buffer)?;
for b in buffer.into_iter().take_while(|&b| b != b'\0') {
f.write_char(b.into())?;
}
}

match self.turn {
Expand All @@ -197,7 +203,7 @@ impl Display for Board {
}

if let Some(ep) = self.en_passant {
write!(f, "{} ", ep)?;
write!(f, "{ep} ")?;
} else {
f.write_str("- ")?;
}
Expand Down Expand Up @@ -230,6 +236,7 @@ pub enum ParseFenError {
impl FromStr for Board {
type Err = ParseFenError;

#[inline(always)]
fn from_str(s: &str) -> Result<Self, Self::Err> {
let fields: Vec<_> = s.split(' ').collect();
let [board, turn, castles, en_passant, halfmoves, fullmoves] = &fields[..] else {
Expand Down
12 changes: 7 additions & 5 deletions lib/chess/castles.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::chess::{Color, Perspective, Piece, Role, Square};
use crate::util::{Bits, Integer};
use derive_more::{Debug, *};
use std::{cell::SyncUnsafeCell, fmt, mem::MaybeUninit, str::FromStr};
use std::fmt::{self, Formatter};
use std::{cell::SyncUnsafeCell, mem::MaybeUninit, str::FromStr};

/// The castling rights in a chess [`Position`][`crate::chess::Position`].
#[derive(
Expand Down Expand Up @@ -107,15 +108,15 @@ impl From<Square> for Castles {
}
}

impl fmt::Display for Castles {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl Display for Castles {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
for side in Color::iter() {
if self.has_short(side) {
fmt::Display::fmt(&Piece::new(Role::King, side), f)?;
Display::fmt(&Piece::new(Role::King, side), f)?;
}

if self.has_long(side) {
fmt::Display::fmt(&Piece::new(Role::Queen, side), f)?;
Display::fmt(&Piece::new(Role::Queen, side), f)?;
}
}

Expand All @@ -131,6 +132,7 @@ pub struct ParseCastlesError;
impl FromStr for Castles {
type Err = ParseCastlesError;

#[inline(always)]
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut castles = Castles::none();

Expand Down
42 changes: 17 additions & 25 deletions lib/chess/file.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
use crate::chess::{Bitboard, Mirror};
use crate::util::Integer;
use derive_more::{Display, Error};
use std::fmt::{self, Formatter, Write};
use std::{ops::Sub, str::FromStr};

/// A column on the chess board.
#[derive(Debug, Display, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(test, derive(test_strategy::Arbitrary))]
#[repr(i8)]
pub enum File {
#[display("a")]
A,
#[display("b")]
B,
#[display("c")]
C,
#[display("d")]
D,
#[display("e")]
E,
#[display("f")]
F,
#[display("g")]
G,
#[display("h")]
H,
}

Expand Down Expand Up @@ -57,30 +50,29 @@ impl Sub for File {
}
}

impl Display for File {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_char((b'a' + self.cast::<u8>()).into())
}
}

/// The reason why parsing [`File`] failed.
#[derive(Debug, Display, Clone, Eq, PartialEq, Error)]
#[display(
"failed to parse file, expected letter in the range `({}..={})`",
File::A,
File::H
)]
#[display("failed to parse file")]
pub struct ParseFileError;

impl FromStr for File {
type Err = ParseFileError;

#[inline(always)]
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"a" => Ok(File::A),
"b" => Ok(File::B),
"c" => Ok(File::C),
"d" => Ok(File::D),
"e" => Ok(File::E),
"f" => Ok(File::F),
"g" => Ok(File::G),
"h" => Ok(File::H),
_ => Err(ParseFileError),
}
let [c] = s.as_bytes() else {
return Err(ParseFileError);
};

c.checked_sub(b'a')
.and_then(Integer::convert)
.ok_or(ParseFileError)
}
}

Expand Down
3 changes: 3 additions & 0 deletions lib/chess/magic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ use crate::chess::{Bitboard, Square};
pub struct Magic(Bitboard, u64, usize);

impl Magic {
#[inline(always)]
pub fn mask(&self) -> Bitboard {
self.0
}

#[inline(always)]
pub fn factor(&self) -> u64 {
self.1
}

#[inline(always)]
pub fn offset(&self) -> usize {
self.2
}
Expand Down
18 changes: 9 additions & 9 deletions lib/chess/move.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::chess::{Bitboard, Perspective, Piece, Rank, Role, Square, Squares};
use crate::util::{Assume, Binary, Bits, Integer};
use std::fmt::{self, Write};
use std::fmt::{self, Debug, Display, Formatter, Write};
use std::{num::NonZeroU16, ops::RangeBounds};

/// A chess move.
Expand Down Expand Up @@ -135,10 +135,10 @@ impl Move {
}
}

impl fmt::Debug for Move {
impl Debug for Move {
#[coverage(off)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self, f)?;
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self, f)?;

if self.is_en_passant() {
f.write_char('^')?;
Expand All @@ -152,13 +152,13 @@ impl fmt::Debug for Move {
}
}

impl fmt::Display for Move {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.whence(), f)?;
fmt::Display::fmt(&self.whither(), f)?;
impl Display for Move {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.whence(), f)?;
Display::fmt(&self.whither(), f)?;

if let Some(r) = self.promotion() {
fmt::Display::fmt(&r, f)?;
Display::fmt(&r, f)?;
}

Ok(())
Expand Down
3 changes: 3 additions & 0 deletions lib/chess/outcome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,19 @@ impl Outcome {
/// Whether the outcome is a [draw] and neither side has won.
///
/// [draw]: https://www.chessprogramming.org/Draw
#[inline(always)]
pub fn is_draw(&self) -> bool {
!self.is_decisive()
}

/// Whether the outcome is a decisive and one of the sides has won.
#[inline(always)]
pub fn is_decisive(&self) -> bool {
matches!(self, Outcome::Checkmate(_))
}

/// The winning side, if the outcome is [decisive](`Self::is_decisive`).
#[inline(always)]
pub fn winner(&self) -> Option<Color> {
match *self {
Outcome::Checkmate(c) => Some(c),
Expand Down
Loading
Loading