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}