dialogue_rs/script/
line.rs1use crate::script::{
7 command::Command,
8 marker::Marker,
9 parser::{Parser, Rule},
10};
11use anyhow::bail;
12use pest::{iterators::Pair, Parser as PestParser};
13use std::fmt;
14
15#[derive(Debug, PartialEq, Eq, Clone)]
17pub enum Line {
18 Command(Command),
20 Marker(Marker),
22}
23
24impl fmt::Display for Line {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 match self {
27 Self::Command(command) => writeln!(f, "{command}"),
28 Self::Marker(marker) => writeln!(f, "{marker}"),
29 }
30 }
31}
32
33impl From<Command> for Line {
34 fn from(command: Command) -> Self {
35 Self::Command(command)
36 }
37}
38
39impl From<Marker> for Line {
40 fn from(marker: Marker) -> Self {
41 Self::Marker(marker)
42 }
43}
44
45impl Line {
46 pub fn command(command: Command) -> Self {
48 Self::Command(command)
49 }
50
51 pub fn parse(line_str: &str) -> Result<Self, anyhow::Error> {
53 let mut pairs = Parser::parse(Rule::Line, line_str)?;
54 let pair = pairs.next().expect("a pair exists");
55 assert_eq!(pairs.next(), None);
56
57 pair.try_into()
58 }
59}
60
61impl TryFrom<Pair<'_, Rule>> for Line {
62 type Error = anyhow::Error;
63
64 fn try_from(pair: Pair<'_, Rule>) -> Result<Self, Self::Error> {
65 match pair.as_rule() {
66 Rule::Line => {
67 let mut pairs = pair.into_inner();
68 let pair = pairs.next().expect("a pair exists");
69 assert_eq!(pairs.next(), None);
70
71 match pair.as_rule() {
72 Rule::Command => Command::parse(pair.as_str()).map(Self::Command),
73 Rule::Marker => Marker::parse(pair.as_str()).map(Self::Marker),
74 _ => unreachable!("Lines can't contain anything other than commands, comments, markers, or blank lines"),
75 }
76 }
77 _ => bail!("Pair is not a line: {:#?}", pair),
78 }
79 }
80}
81
82#[cfg(test)]
83mod test {
84 use crate::script::command::Command;
85
86 use super::Line;
87
88 #[test]
89 fn test_parse_line() {
90 let expected = Line::Command(Command::new(
91 "SAY",
92 Some("Zelda"),
93 Some("\"I don't actually have anything to say\""),
94 ));
95 let actual = Line::parse("Zelda |SAY| \"I don't actually have anything to say\"\n\n")
96 .expect("command is valid");
97
98 assert_eq!(expected, actual);
99 }
100
101 #[test]
102 fn test_round_trip() {
103 let input = "|SAY| Does this work?\n";
104 let line = Line::parse(input).expect("line is valid");
105 let output = line.to_string();
106
107 assert_eq!(input, output);
108 }
109}