ayaka_bindings_types/config.rs
1use ayaka_primitive::RawValue;
2use fallback::FallbackSpec;
3use serde::{Deserialize, Serialize};
4use std::{
5 borrow::Cow,
6 collections::{HashMap, VecDeque},
7};
8
9/// The unit of one line in an action.
10///
11/// If a frontend supports animation,
12/// the characters in [`ActionSubText::Chars`] should be printed one by one,
13/// while the characters in [`ActionSubText::Block`] should be printed together.
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(tag = "type", content = "data")]
16pub enum ActionSubText {
17 /// Characters printed one by one.
18 /// Usually they are meaningful texts.
19 Chars(String),
20 /// Characters printed together.
21 /// Usually they are HTML tags or other control characters.
22 Block(String),
23}
24
25impl ActionSubText {
26 /// Creates [`ActionSubText::Chars`].
27 pub fn chars(s: impl Into<String>) -> Self {
28 Self::Chars(s.into())
29 }
30
31 /// Creates [`ActionSubText::Block`].
32 pub fn block(s: impl Into<String>) -> Self {
33 Self::Block(s.into())
34 }
35
36 /// Gets a reference of [`str`].
37 pub fn as_str(&self) -> &str {
38 match self {
39 Self::Chars(s) | Self::Block(s) => s,
40 }
41 }
42
43 /// Gets the inner [`String`].
44 pub fn into_string(self) -> String {
45 match self {
46 Self::Chars(s) | Self::Block(s) => s,
47 }
48 }
49}
50
51/// A map from variable name to [`RawValue`].
52pub type VarMap = HashMap<String, RawValue>;
53
54/// The serializable context.
55#[derive(Debug, Default, Clone, Deserialize, Serialize)]
56pub struct RawContext {
57 /// Current base paragraph tag.
58 pub cur_base_para: String,
59 /// Current paragraph tag.
60 pub cur_para: String,
61 /// Current text index.
62 pub cur_act: usize,
63 /// Current local variables.
64 pub locals: VarMap,
65}
66
67/// The `text` is a [`VecDeque<ActionSubText>`].
68/// The [`ActionSubText`] could be pushed and poped at front or back.
69///
70/// Generally, you should avoid using `push_back` directly.
71/// To reduce allocations in serialization, you should use
72/// `push_back_chars` and `push_back_block`.
73///
74/// ```
75/// # use ayaka_bindings_types::*;
76/// let mut text = ActionText::default();
77/// text.push_back_chars("Hello ");
78/// assert_eq!(text.text[0], ActionSubText::chars("Hello "));
79/// text.push_back_chars("world!");
80/// assert_eq!(text.text[0], ActionSubText::chars("Hello world!"));
81/// ```
82#[derive(Debug, Default, Clone, Serialize, Deserialize, FallbackSpec)]
83pub struct ActionText {
84 /// The full texts.
85 pub text: VecDeque<ActionSubText>,
86 /// The key of current character.
87 pub ch_key: Option<String>,
88 /// The current character.
89 pub character: Option<String>,
90 /// The temp variables.
91 pub vars: VarMap,
92}
93
94impl ActionText {
95 /// Push the string as [`ActionSubText::Chars`] to the back.
96 /// If the back element is also [`ActionSubText::Chars`], the string is appended.
97 pub fn push_back_chars<'a>(&mut self, s: impl Into<Cow<'a, str>>) {
98 let s = s.into();
99 if let Some(ActionSubText::Chars(text)) = self.text.back_mut() {
100 text.push_str(&s);
101 } else {
102 self.text.push_back(ActionSubText::chars(s));
103 }
104 }
105
106 /// Push the string as [`ActionSubText::Block`] to the back.
107 /// If the back element is also [`ActionSubText::Block`], the string is appended.
108 pub fn push_back_block<'a>(&mut self, s: impl Into<Cow<'a, str>>) {
109 let s = s.into();
110 if let Some(ActionSubText::Block(text)) = self.text.back_mut() {
111 text.push_str(&s);
112 } else {
113 self.text.push_back(ActionSubText::block(s));
114 }
115 }
116}
117
118impl std::fmt::Display for ActionText {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 for text in &self.text {
121 write!(f, "{}", text.as_str())?;
122 }
123 Ok(())
124 }
125}
126
127impl PartialEq for ActionText {
128 fn eq(&self, other: &Self) -> bool {
129 self.to_string() == other.to_string()
130 && self.ch_key == other.ch_key
131 && self.character == other.character
132 && self.vars == other.vars
133 }
134}
135
136/// The full action information in one line of config.
137/// It provides the full texts and other properties exacted from [`ayaka_primitive::Text`].
138#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
139#[serde(tag = "type", content = "data")]
140pub enum Action {
141 /// An empty action usually means an `exec` or custom action.
142 #[default]
143 Empty,
144 /// A text action, display some texts.
145 Text(ActionText),
146 /// A switch action, display switches and let player to choose.
147 Switches(Vec<Switch>),
148 /// A custom action.
149 Custom(VarMap),
150}
151
152/// One switch in the switches of an [`Action`].
153#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, FallbackSpec)]
154pub struct Switch {
155 /// The switch text.
156 pub text: String,
157 /// Whether the switch is enabled.
158 pub enabled: bool,
159}