sgf_parse/game_tree.rs
1use std::fmt::Debug;
2
3use crate::{go, unknown_game, SgfNode, SgfParseError};
4
5/// The game recorded in a [`GameTree`].
6///
7/// Any [`GameTree`] retured by [`parse`](`crate::parse`) will have a game type which corresponds to
8/// the SGF `GM` property of the root node.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum GameType {
11 Go,
12 Unknown,
13}
14
15/// An SGF [GameTree](https://www.red-bean.com/sgf/sgf4.html#ebnf-def) value.
16///
17/// This type allows creating a collection of [`SgfNode`] values for different games. This is
18/// used in the return type of the [`parse`](`crate::parse()`) function. Users of the
19/// [`serialize`](`crate::serialize()`) function will need to build these.
20///
21/// For now, all non-Go games will parse as [`GameTree::Unknown`] which should also be used for any
22/// serialization of non-Go games.
23#[derive(Clone, Debug, PartialEq)]
24pub enum GameTree {
25 GoGame(SgfNode<go::Prop>),
26 Unknown(SgfNode<unknown_game::Prop>),
27}
28
29impl GameTree {
30 /// Consumes a Go game `GameTree` and returns the contained [`SgfNode`].
31 ///
32 /// This is a convenience method for go games.
33 ///
34 /// # Errors
35 /// Returns an error if the variant isn't a [`GameTree::GoGame`].
36 ///
37 /// # Examples
38 /// ```
39 /// use sgf_parse::parse;
40 ///
41 /// let gametree = parse("(;B[de]C[A comment])").unwrap().into_iter().next().unwrap();
42 /// let sgf_node = gametree.into_go_node().unwrap();
43 /// ```
44 pub fn into_go_node(self) -> Result<SgfNode<go::Prop>, SgfParseError> {
45 match self {
46 Self::GoGame(sgf_node) => Ok(sgf_node),
47 _ => Err(SgfParseError::UnexpectedGameType),
48 }
49 }
50
51 /// Return a reference to the root [`SgfNode`] of the tree.
52 ///
53 /// This is a convenience method for go games.
54 ///
55 /// # Errors
56 /// Returns an error if the variant isn't a [`GameTree::GoGame`].
57 ///
58 /// # Examples
59 /// ```
60 /// use sgf_parse::parse;
61 ///
62 /// let gametrees = parse("(;B[de]C[A comment])").unwrap();
63 /// let sgf_node = gametrees.first().unwrap().as_go_node().unwrap();
64 /// ```
65 pub fn as_go_node(&self) -> Result<&'_ SgfNode<go::Prop>, SgfParseError> {
66 match self {
67 Self::GoGame(sgf_node) => Ok(sgf_node),
68 _ => Err(SgfParseError::UnexpectedGameType),
69 }
70 }
71
72 /// Returns the [`GameType`] for this [`GameTree`].
73 ///
74 /// # Examples
75 /// ```
76 /// use sgf_parse::{parse, GameType};
77 ///
78 /// let gametree = parse("(;GM[1]B[de]C[A comment])").unwrap().into_iter().next().unwrap();
79 /// assert_eq!(gametree.gametype(), GameType::Go);
80 /// ```
81 pub fn gametype(&self) -> GameType {
82 match self {
83 Self::GoGame(_) => GameType::Go,
84 Self::Unknown(_) => GameType::Unknown,
85 }
86 }
87}
88
89impl std::fmt::Display for GameTree {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 let node_text = match self {
92 Self::GoGame(sgf_node) => sgf_node.serialize(),
93 Self::Unknown(sgf_node) => sgf_node.serialize(),
94 };
95 std::fmt::Display::fmt(&node_text, f)
96 }
97}
98
99impl std::convert::From<SgfNode<go::Prop>> for GameTree {
100 fn from(sgf_node: SgfNode<go::Prop>) -> Self {
101 Self::GoGame(sgf_node)
102 }
103}
104
105impl std::convert::From<SgfNode<unknown_game::Prop>> for GameTree {
106 fn from(sgf_node: SgfNode<unknown_game::Prop>) -> Self {
107 Self::Unknown(sgf_node)
108 }
109}