use std::str::FromStr;
use super::SgfPropError;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Color {
Black,
White,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Double {
One,
Two,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct SimpleText {
pub text: String,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Text {
pub text: String,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PropertyType {
Move,
Setup,
Root,
GameInfo,
Inherit,
}
impl FromStr for Double {
type Err = SgfPropError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "1" {
Ok(Self::One)
} else if s == "2" {
Ok(Self::Two)
} else {
Err(SgfPropError {})
}
}
}
impl FromStr for Color {
type Err = SgfPropError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "B" {
Ok(Self::Black)
} else if s == "W" {
Ok(Self::White)
} else {
Err(SgfPropError {})
}
}
}
impl std::convert::From<&str> for SimpleText {
fn from(s: &str) -> Self {
Self { text: s.to_owned() }
}
}
impl std::convert::From<&str> for Text {
fn from(s: &str) -> Self {
Self { text: s.to_owned() }
}
}
impl FromStr for SimpleText {
type Err = SgfPropError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(s.into())
}
}
impl FromStr for Text {
type Err = SgfPropError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(s.into())
}
}
impl std::fmt::Display for SimpleText {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = format_text(&self.text)
.replace("\r\n", " ")
.replace("\n\r", " ")
.replace(['\n', '\r'], " ");
f.write_str(&text)
}
}
impl std::fmt::Display for Text {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = format_text(&self.text);
f.write_str(&text)
}
}
fn format_text(s: &str) -> String {
let mut output = vec![];
let chars: Vec<char> = s.chars().collect();
let mut i = 0;
while i < chars.len() {
let c = chars[i];
if c == '\\' && i + 1 < chars.len() {
i += 1;
if chars[i] == '\n' {
if i + 1 < chars.len() && chars[i + 1] == '\r' {
i += 1;
}
} else if chars[i] == '\r' {
if i + 1 < chars.len() && chars[i + 1] == '\n' {
i += 1;
}
} else {
output.push(chars[i]);
}
} else if c.is_whitespace() && c != '\r' && c != '\n' {
if i + 1 < chars.len() {
let next = chars[i + 1];
if (c == '\n' && next == '\r') || (c == '\r' && next == '\n') {
i += 1;
}
}
output.push(' ');
} else {
output.push(c);
}
i += 1;
}
output.into_iter().collect()
}
#[cfg(test)]
mod test {
#[test]
pub fn format_text() {
let text = super::Text {
text: "Comment with\trandom whitespace\nescaped \\] and \\\\ and a soft \\\nlinebreak"
.to_string(),
};
let expected = "Comment with random whitespace\nescaped ] and \\ and a soft linebreak";
assert_eq!(format!("{}", text), expected);
}
#[test]
pub fn format_simple_text() {
let text = super::SimpleText { text:
"Comment with\trandom\r\nwhitespace\n\rescaped \\] and \\\\ and\na soft \\\nlinebreak"
.to_string()
};
let expected = "Comment with random whitespace escaped ] and \\ and a soft linebreak";
assert_eq!(format!("{}", text), expected);
}
}