sgf_parse/
unknown_game.rs

1//! Generic types for SGFs without a known game.
2//!
3//! This module contains a generic [`SgfProp`] implementation appropriate
4//! for use with any SGF file. This implementation recognizes all [general
5//! properties](https://www.red-bean.com/sgf/properties.html), but any game
6//! specific property will parse as [`Prop::Unknown`].
7//!
8//! SGF Move, Point, and Stone values are all simply stored as strings.
9
10use crate::props::parse::FromCompressedList;
11use crate::props::{PropertyType, SgfPropError, ToSgf};
12use crate::{InvalidNodeError, SgfProp};
13use std::collections::HashSet;
14
15sgf_prop! {
16    Prop, String, String, String,
17    { }
18}
19
20/// An SGF [Point](https://www.red-bean.com/sgf/go.html#types) value for an unknown game.
21pub type Point = String;
22
23/// An SGF [Stone](https://www.red-bean.com/sgf/go.html#types) value for an unknown game.
24pub type Stone = String;
25
26/// An SGF [Move](https://www.red-bean.com/sgf/go.html#types) value for an unknown game.
27pub type Move = String;
28
29impl SgfProp for Prop {
30    type Point = Point;
31    type Stone = Stone;
32    type Move = Move;
33
34    fn new(identifier: String, values: Vec<String>) -> Self {
35        Self::parse_general_prop(identifier, values)
36    }
37
38    fn identifier(&self) -> String {
39        match self.general_identifier() {
40            Some(identifier) => identifier,
41            None => panic!("Unimplemented identifier for {:?}", self),
42        }
43    }
44
45    fn property_type(&self) -> Option<PropertyType> {
46        self.general_property_type()
47    }
48
49    fn validate_properties(properties: &[Self], is_root: bool) -> Result<(), InvalidNodeError> {
50        Self::general_validate_properties(properties, is_root)
51    }
52}
53
54impl std::fmt::Display for Prop {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        let prop_string = match self.serialize_prop_value() {
57            Some(s) => s,
58            None => panic!("Unimplemented identifier for {:?}", self),
59        };
60        write!(f, "{}[{}]", self.identifier(), prop_string)
61    }
62}
63
64impl FromCompressedList for String {
65    fn from_compressed_list(ul: &Self, lr: &Self) -> Result<HashSet<Self>, SgfPropError> {
66        // For an unknown game we have no way to parse a compressed list, but since points
67        // are just strings we can just return a single point with that string and let the
68        // user decide what to do with it.
69        let mut points = HashSet::new();
70        points.insert(format!("{ul}:{lr}"));
71        Ok(points)
72    }
73}
74
75impl ToSgf for String {
76    fn to_sgf(&self) -> String {
77        self.to_owned()
78    }
79}