Skip to content

Commit b9083de

Browse files
committed
0.5.1
add option to use San instead of SanPlus
1 parent 16c085d commit b9083de

File tree

7 files changed

+106
-62
lines changed

7 files changed

+106
-62
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rpgn"
3-
version = "0.5.0"
3+
version = "0.5.1"
44
edition = "2021"
55
authors = ["Leonard D. <tigerros.gh@gmail.com>"]
66
description = "A crate for parsing PGNs (Portable [Chess] Game Notation)."

benches/pgn.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
22
use rpgn::samples::{sans0, sans1, variation0, variation1, variation2, PgnSample};
33
use rpgn::Pgn;
44
use rpgn::{Sans, Variation};
5+
use shakmaty::san::SanPlus;
56

6-
fn sans_samples() -> [PgnSample<Sans>; 2] {
7+
fn sans_samples() -> [PgnSample<Sans<SanPlus>>; 2] {
78
[sans0(), sans1()]
89
}
910

10-
fn variation_samples() -> [PgnSample<Variation>; 3] {
11+
fn variation_samples() -> [PgnSample<Variation<SanPlus>>; 3] {
1112
[variation0(), variation1(), variation2()]
1213
}
1314

@@ -69,7 +70,7 @@ pub fn from_pgn(c: &mut Criterion) {
6970
group.bench_with_input(
7071
BenchmarkId::from_parameter(id),
7172
&pgn_string,
72-
|b, pgn_string| b.iter(|| Pgn::<Sans>::from_str(pgn_string)),
73+
|b, pgn_string| b.iter(|| Pgn::<Sans<SanPlus>>::from_str(pgn_string)),
7374
);
7475
}
7576

@@ -89,7 +90,7 @@ pub fn from_pgn(c: &mut Criterion) {
8990
group.bench_with_input(
9091
BenchmarkId::from_parameter(id),
9192
&pgn_string,
92-
|b, pgn_string| b.iter(|| Pgn::<Variation>::from_str(pgn_string)),
93+
|b, pgn_string| b.iter(|| Pgn::<Variation<SanPlus>>::from_str(pgn_string)),
9394
);
9495
}
9596

examples/example.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rpgn::{Pgn, Sans, Variation};
2+
use shakmaty::san::{San, SanPlus};
23

34
const PGN: &str = r#"[Event "Live Chess"]
45
[Site "Chess.com"]
@@ -34,9 +35,9 @@ Bg4 9. Qa1 d4 10. h3 dxe3 11. fxe3 Bf5 12. Nf3 Nb4 13. O-O Nxc2 14. Nxc2 Bxc2
3435
Bxg7 Qd7 22. Bh6 Ne4 23. Bg4 Qe7 (23... Qe7 24. Be6+) 1-0"#;
3536

3637
fn main() {
37-
let simple_pgn = Pgn::<Sans>::from_str(PGN);
38-
let variation_pgn = Pgn::<Variation>::from_str(PGN);
38+
let simple_pgn = Pgn::<Sans<San>>::from_str(PGN);
39+
let full_pgn = Pgn::<Variation<SanPlus>>::from_str(PGN);
3940

40-
println!("Simple parsed PGN: {simple_pgn:#?}");
41-
println!("Parsed PGN with variations: {variation_pgn:#?}");
41+
println!("Parsed PGN with simple movetext: {simple_pgn:#?}");
42+
println!("Parsed PGN with variations: {full_pgn:#?}");
4243
}

src/movetext/sans.rs

+30-12
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1-
use shakmaty::san::SanPlus;
1+
use shakmaty::san::{San, SanPlus};
22
use std::fmt::{Display, Formatter, Write};
33
use crate::{MoveNumber, Movetext};
4+
use crate::movetext::{SanWithVariations, Variation};
45

5-
/// Use if you don't care about variations.
6+
/// A vec of SANs. Use if you don't care about variations.
7+
///
8+
/// Why is there a generic? To allow usage of either a [`San`] or a [`SanPlus`].
9+
/// A [`San`] is often sufficient and is smaller than a [`SanPlus`], so use a [`San`]
10+
/// unless you need the [`SanPlus`] suffix.
11+
///
12+
/// Only implements [`Movetext`] if `S` is [`San`] or [`SanPlus`].
613
#[derive(Clone, Debug, PartialEq, Eq)]
7-
pub struct Sans(pub Vec<SanPlus>);
8-
9-
use crate::movetext::{SanWithVariations, Variation};
14+
pub struct Sans<S>(pub Vec<S>);
1015

11-
impl From<Variation> for Sans {
16+
impl<S> From<Variation<S>> for Sans<S> {
1217
/// Takes the root variation of the given [`Variation`] and transfers it to a [`Sans`].
13-
fn from(variation: Variation) -> Self {
18+
fn from(variation: Variation<S>) -> Self {
1419
let mut san_vec = Self(Vec::with_capacity(variation.0.len()));
1520

1621
for SanWithVariations { san, .. } in variation.0 {
@@ -21,7 +26,7 @@ impl From<Variation> for Sans {
2126
}
2227
}
2328

24-
impl Display for Sans {
29+
impl<S> Display for Sans<S> where S: Display {
2530
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2631
let mut move_number = MoveNumber(0);
2732
let mut first_move = true;
@@ -54,10 +59,23 @@ impl Display for Sans {
5459
}
5560
}
5661

57-
impl Movetext for Sans {
58-
type Agent = Self;
62+
macro_rules! base_movetext_impl {
63+
() => {
64+
type Agent = Self;
65+
66+
fn begin_game() -> Self { Self(Vec::with_capacity(100)) }
67+
fn end_game(agent: Self) -> Self { agent }
68+
};
69+
}
70+
71+
impl Movetext for Sans<San> {
72+
base_movetext_impl! {}
73+
74+
fn san(agent: &mut Self, san: SanPlus) { agent.0.push(san.san); }
75+
}
5976

60-
fn begin_game() -> Self { Self(Vec::with_capacity(100)) }
77+
impl Movetext for Sans<SanPlus> {
78+
base_movetext_impl! {}
79+
6180
fn san(agent: &mut Self, san: SanPlus) { agent.0.push(san); }
62-
fn end_game(agent: Self) -> Self { agent }
6381
}

src/movetext/variation.rs

+55-34
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
use std::fmt::{Display, Formatter, Write};
22
use pgn_reader::Skip;
3-
use shakmaty::san::SanPlus;
3+
use shakmaty::san::{San, SanPlus};
44
use crate::{MoveNumber, Movetext, movetext::Sans};
55

6+
/// See [`Variation`].
67
#[derive(Debug, PartialEq, Eq, Clone)]
7-
pub struct SanWithVariations {
8-
pub san: SanPlus,
9-
pub variations: Vec<Variation>,
8+
pub struct SanWithVariations<S> {
9+
pub san: S,
10+
pub variations: Vec<Variation<S>>,
1011
}
1112

13+
/// A vec of SANs with variations. Use if you do care about variations.
14+
///
15+
/// Regarding the generic `S`, see the docs for [`Sans`].
1216
#[derive(Debug, PartialEq, Eq, Clone)]
13-
/// Use if you do care about variations.
14-
pub struct Variation(pub Vec<SanWithVariations>);
17+
pub struct Variation<S>(pub Vec<SanWithVariations<S>>);
1518

16-
impl From<Sans> for Variation {
17-
fn from(san_vec: Sans) -> Self {
19+
impl<S> From<Sans<S>> for Variation<S> {
20+
fn from(san_vec: Sans<S>) -> Self {
1821
let mut variation_movetext = Self(Vec::with_capacity(san_vec.0.len()));
1922

2023
for san in san_vec.0 {
@@ -25,7 +28,7 @@ impl From<Sans> for Variation {
2528
}
2629
}
2730

28-
impl Variation {
31+
impl<S> Variation<S> where S: Display {
2932
fn fmt(&self, f: &mut Formatter<'_>, mut move_number: MoveNumber, mut very_first_move: bool) -> std::fmt::Result {
3033
for SanWithVariations { san, variations } in &self.0 {
3134
if very_first_move {
@@ -62,7 +65,7 @@ impl Variation {
6265
}
6366
}
6467

65-
impl Display for Variation {
68+
impl<S> Display for Variation<S> where S: Display {
6669
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
6770
self.fmt(f, MoveNumber::MIN, true)
6871
}
@@ -71,45 +74,63 @@ impl Display for Variation {
7174
#[derive(Debug)]
7275
#[doc(hidden)]
7376
/// Only used in [`Variation`]'s implementation of [`Movetext`].
74-
pub struct VariationAgent {
75-
root_variation: Variation,
76-
variation_layers: Vec<Variation>
77+
pub struct VariationAgent<S> {
78+
root_variation: Variation<S>,
79+
variation_layers: Vec<Variation<S>>
7780
}
7881

79-
impl Movetext for Variation {
80-
type Agent = VariationAgent;
82+
macro_rules! base_movetext_impl {
83+
() => {
84+
fn begin_game() -> Self::Agent {
85+
VariationAgent {
86+
root_variation: Self(Vec::new()),
87+
variation_layers: Vec::new()
88+
}
89+
}
8190

82-
fn begin_game() -> Self::Agent {
83-
VariationAgent {
84-
root_variation: Self(Vec::new()),
85-
variation_layers: Vec::new()
91+
fn begin_variation(agent: &mut Self::Agent) -> Skip {
92+
agent.variation_layers.push(Self(Vec::new()));
93+
94+
Skip(false)
8695
}
87-
}
8896

89-
fn begin_variation(agent: &mut Self::Agent) -> Skip {
90-
agent.variation_layers.push(Self(Vec::new()));
97+
fn end_variation(agent: &mut Self::Agent) {
98+
let Some(ending_variation) = agent.variation_layers.pop() else {
99+
return;
100+
};
91101

92-
Skip(false)
93-
}
102+
let ending_variation_parent = agent.variation_layers.last_mut().unwrap_or(&mut agent.root_variation);
103+
104+
#[allow(clippy::unwrap_used)]
105+
ending_variation_parent.0.last_mut().unwrap().variations.push(ending_variation);
106+
}
107+
108+
fn end_game(agent: Self::Agent) -> Self {
109+
agent.root_variation
110+
}
111+
};
112+
}
94113

95-
fn end_variation(agent: &mut Self::Agent) {
96-
let Some(ending_variation) = agent.variation_layers.pop() else {
97-
return;
98-
};
114+
impl Movetext for Variation<San> {
115+
type Agent = VariationAgent<San>;
99116

100-
let ending_variation_parent = agent.variation_layers.last_mut().unwrap_or(&mut agent.root_variation);
117+
fn san(agent: &mut Self::Agent, san: SanPlus) {
118+
let current_variation = agent.variation_layers.last_mut().unwrap_or(&mut agent.root_variation);
101119

102-
#[allow(clippy::unwrap_used)]
103-
ending_variation_parent.0.last_mut().unwrap().variations.push(ending_variation);
120+
current_variation.0.push(SanWithVariations { san: san.san, variations: Vec::new() });
104121
}
105122

123+
base_movetext_impl! {}
124+
}
125+
126+
impl Movetext for Variation<SanPlus> {
127+
type Agent = VariationAgent<SanPlus>;
128+
106129
fn san(agent: &mut Self::Agent, san: SanPlus) {
107130
let current_variation = agent.variation_layers.last_mut().unwrap_or(&mut agent.root_variation);
108131

109132
current_variation.0.push(SanWithVariations { san, variations: Vec::new() });
110133
}
111134

112-
fn end_game(agent: Self::Agent) -> Self {
113-
agent.root_variation
114-
}
135+
base_movetext_impl! {}
115136
}

src/pgn.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use shakmaty::fen::{Fen, ParseFenError};
66
use super::visitor::{Visitor};
77
use crate::{Eco, Outcome, Date, Round, RawHeaderOwned, Movetext};
88

9+
/// The generic `M` should be a struct that implements [`Movetext`].
910
#[derive(Clone, Debug, PartialEq, Eq)]
1011
pub struct Pgn<M> {
1112
/// See "Event" under "Seven Tag Roster".
@@ -164,20 +165,21 @@ impl<M> Display for Pgn<M> where M: Display {
164165
#[allow(clippy::unreachable)]
165166
#[allow(clippy::panic)]
166167
mod tests {
168+
use shakmaty::san::SanPlus;
167169
use test_case::test_case;
168170
use crate::movetext::{Sans, Variation};
169171
use crate::samples::*;
170172

171173
#[test_case(&sans0())]
172174
#[test_case(&sans1())]
173-
fn san_vec_to_pgn_from_pgn(sample: &PgnSample<Sans>) {
175+
fn san_vec_to_pgn_from_pgn(sample: &PgnSample<Sans<SanPlus>>) {
174176
sample.test();
175177
}
176178

177179
#[test_case(&variation0())]
178180
#[test_case(&variation1())]
179181
#[test_case(&variation2())]
180-
fn variation_to_pgn_from_pgn(sample: &PgnSample<Variation>) {
182+
fn variation_to_pgn_from_pgn(sample: &PgnSample<Variation<SanPlus>>) {
181183
sample.test();
182184
}
183185
}

src/samples.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use pgn_reader::RawHeader;
1313
#[cfg(test)]
1414
use pretty_assertions::assert_eq;
1515
use shakmaty::fen::Fen;
16+
use shakmaty::san::SanPlus;
1617
use shakmaty::Color;
1718
use std::fmt::Debug;
1819
#[cfg(test)]
@@ -60,7 +61,7 @@ where
6061
}
6162
}
6263

63-
pub fn variation0() -> PgnSample<Variation> {
64+
pub fn variation0() -> PgnSample<Variation<SanPlus>> {
6465
const PGN: &str = r#"[Event "Let's Play!"]
6566
[Site "Chess.com"]
6667
[Date "2024.02.14"]
@@ -112,7 +113,7 @@ pub fn variation0() -> PgnSample<Variation> {
112113
)
113114
}
114115

115-
pub fn variation1() -> PgnSample<Variation> {
116+
pub fn variation1() -> PgnSample<Variation<SanPlus>> {
116117
const PGN: &str = r#"[Event "Live Chess"]
117118
[Site "Lichess"]
118119
[Date "2024.02.??"]
@@ -156,7 +157,7 @@ pub fn variation1() -> PgnSample<Variation> {
156157
)
157158
}
158159

159-
pub fn variation2() -> PgnSample<Variation> {
160+
pub fn variation2() -> PgnSample<Variation<SanPlus>> {
160161
const PGN: &str = r#"[Date "????.01.??"]
161162
[Round "1"]
162163
[Result "1/2-1/2"]
@@ -200,7 +201,7 @@ pub fn variation2() -> PgnSample<Variation> {
200201
}
201202

202203
/// Nd2 is ambiguous, but we don't care.
203-
pub fn sans0() -> PgnSample<Sans> {
204+
pub fn sans0() -> PgnSample<Sans<SanPlus>> {
204205
const PGN: &str = r#"[FEN "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"]
205206
206207
1. Nf3 1... a6 2. d3 2... a5 3. Nd2"#;
@@ -221,7 +222,7 @@ pub fn sans0() -> PgnSample<Sans> {
221222
}
222223

223224
/// One move.
224-
pub fn sans1() -> PgnSample<Sans> {
225+
pub fn sans1() -> PgnSample<Sans<SanPlus>> {
225226
const PGN: &str = "1. e4";
226227

227228
let movetext = sans!(b"e4");

0 commit comments

Comments
 (0)