1use crate::error::{DisplayError, DisplayResult, FormatCode::Tag as TagCode};
2use crate::script_type::ScriptType;
3use crate::util::illegal_name;
4use crate::util::{impl_de_by_from_str, impl_ser_by_to_string};
5use fxhash::FxHashSet as HashSet;
6use std::fmt::{Display, Formatter, Result as FmtResult};
7use std::str::FromStr;
8
9pub type TagSet = HashSet<Tag>;
10
11#[derive(Debug, Clone, Eq, PartialEq, Default)]
12pub struct TagSelectorGroup(Vec<TagSelector>);
13impl TagSelectorGroup {
14 pub fn push(&mut self, selector: TagSelector) {
15 if selector.append {
16 self.0.push(selector);
17 } else {
18 self.0 = vec![selector];
19 }
20 }
21 pub fn select(&self, tags: &TagSet, ty: &ScriptType) -> bool {
22 let mut pass = false;
23 for f in self.0.iter() {
24 let res = f.select(tags, ty);
25 match res {
26 SelectResult::MandatoryFalse => return false,
27 SelectResult::Normal(res) => pass = res,
28 SelectResult::None => (),
29 }
30 }
31 pass
32 }
33}
34impl From<TagSelector> for TagSelectorGroup {
35 fn from(t: TagSelector) -> Self {
36 TagSelectorGroup(vec![t])
37 }
38}
39
40#[derive(Debug, Clone, Eq, PartialEq)]
41pub struct TagSelector {
42 tags: TagGroup,
43 pub append: bool,
44}
45impl_de_by_from_str!(TagSelector);
46impl_ser_by_to_string!(TagSelector);
47
48#[derive(Debug, Clone, Eq, PartialEq, Default)]
49pub struct TagGroup(Vec<TagControl>);
50impl_de_by_from_str!(TagGroup);
51impl_ser_by_to_string!(TagGroup);
52
53#[derive(Debug, Clone, Eq, PartialEq)]
54pub struct TagControl {
55 allow: bool,
56 mandatory: bool,
57 tag: TagOrType,
58}
59
60#[derive(Debug, Clone, Eq, PartialEq, Display)]
61pub enum TagOrType {
62 #[display(fmt = "@{}", _0)]
63 Type(ScriptType),
64 #[display(fmt = "{}", _0)]
65 Tag(Tag),
66}
67impl_de_by_from_str!(TagOrType);
68impl_ser_by_to_string!(TagOrType);
69impl FromStr for TagOrType {
70 type Err = DisplayError;
71 fn from_str(s: &str) -> DisplayResult<Self> {
72 Ok(if s.starts_with('@') {
73 TagOrType::Type(s[1..].parse()?)
74 } else {
75 TagOrType::Tag(s.parse()?)
76 })
77 }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
81pub struct Tag(String);
82impl AsRef<str> for Tag {
83 fn as_ref(&self) -> &str {
84 &self.0
85 }
86}
87impl Tag {
88 pub fn match_all(&self) -> bool {
89 &self.0 == "all"
91 }
92 pub fn new_unchecked(s: String) -> Self {
93 Tag(s)
94 }
95}
96impl FromStr for Tag {
97 type Err = DisplayError;
98 fn from_str(s: &str) -> DisplayResult<Self> {
99 if illegal_name(s) {
100 log::error!("標籤格式不符:{}", s);
101 return TagCode.to_display_res(s.to_owned());
102 }
103 Ok(Tag(s.to_owned()))
104 }
105}
106impl FromStr for TagControl {
107 type Err = DisplayError;
108 fn from_str(mut s: &str) -> DisplayResult<Self> {
109 let allow = if s.starts_with('^') {
110 s = &s[1..s.len()];
111 false
112 } else {
113 true
114 };
115 let mandatory = if s.ends_with(MANDATORY_SUFFIX) {
116 s = &s[0..(s.len() - MANDATORY_SUFFIX.len())];
117 true
118 } else {
119 false
120 };
121 Ok(TagControl {
122 tag: s.parse()?,
123 allow,
124 mandatory,
125 })
126 }
127}
128const MANDATORY_SUFFIX: &str = "!";
129const APPEND_PREFIX: &str = "+";
130impl FromStr for TagSelector {
131 type Err = DisplayError;
132 fn from_str(mut s: &str) -> DisplayResult<Self> {
133 let append = if s.starts_with(APPEND_PREFIX) {
134 s = &s[APPEND_PREFIX.len()..];
135 true
136 } else {
137 false
138 };
139
140 Ok(TagSelector {
141 tags: s.parse()?,
142 append,
143 })
144 }
145}
146
147impl Display for TagSelector {
148 fn fmt(&self, w: &mut Formatter<'_>) -> FmtResult {
149 if self.append {
150 write!(w, "{}", APPEND_PREFIX)?;
151 }
152 write!(w, "{}", self.tags)?;
153 Ok(())
154 }
155}
156
157impl TagSelector {
158 pub fn push(&mut self, other: Self) {
159 if other.append {
160 self.tags.0.extend(other.tags.0.into_iter());
161 } else {
162 *self = other
163 }
164 }
165 pub fn fill_allowed_map<U>(self, set: &mut std::collections::HashSet<Tag, U>)
166 where
167 U: std::hash::BuildHasher,
168 {
169 for control in self.tags.0.into_iter() {
170 let tag = match control.tag {
171 TagOrType::Type(_) => continue, TagOrType::Tag(t) => t,
173 };
174 if control.allow {
175 if tag.match_all() {
177 continue;
178 }
179 set.insert(tag);
180 } else {
181 if tag.match_all() {
182 set.clear(); continue;
184 }
185 set.remove(&tag);
186 }
187 }
188 }
189 pub fn into_allowed_iter(self) -> impl Iterator<Item = Tag> {
190 let mut set = HashSet::default();
191 self.fill_allowed_map(&mut set);
192 set.into_iter()
193 }
194 pub fn select(&self, tags: &TagSet, ty: &ScriptType) -> SelectResult {
195 self.tags.select(tags, ty)
196 }
197}
198
199impl FromStr for TagGroup {
200 type Err = DisplayError;
201 fn from_str(s: &str) -> DisplayResult<Self> {
202 let mut tags = vec![];
203 if !s.is_empty() {
204 for ctrl in s.split(',') {
205 tags.push(ctrl.parse()?);
206 }
207 }
208 Ok(TagGroup(tags))
209 }
210}
211
212impl Display for TagGroup {
213 fn fmt(&self, w: &mut Formatter<'_>) -> FmtResult {
214 let mut first = true;
215 for f in self.0.iter() {
216 if !first {
217 write!(w, ",")?;
218 }
219 first = false;
220 if !f.allow {
221 write!(w, "^")?;
222 }
223 write!(w, "{}", f.tag)?;
224 if f.mandatory {
225 write!(w, "{}", MANDATORY_SUFFIX)?;
226 }
227 }
228 Ok(())
229 }
230}
231
232pub enum SelectResult {
233 None,
234 MandatoryFalse,
235 Normal(bool),
236}
237impl SelectResult {
238 pub fn is_true(&self) -> bool {
239 matches!(self, SelectResult::Normal(true))
240 }
241}
242
243impl TagGroup {
244 pub fn select(&self, tags: &TagSet, ty: &ScriptType) -> SelectResult {
245 let mut pass = SelectResult::None;
246 for ctrl in self.0.iter() {
247 let hit = match &ctrl.tag {
248 TagOrType::Type(t) => ty == t,
249 TagOrType::Tag(t) => t.match_all() || tags.contains(t),
250 };
251 if ctrl.mandatory {
252 if ctrl.allow {
253 if !hit {
254 return SelectResult::MandatoryFalse;
255 }
256 } else {
257 if hit {
258 return SelectResult::MandatoryFalse;
259 }
260 }
261 }
262 if hit {
263 pass = SelectResult::Normal(ctrl.allow);
264 }
265 }
266 pass
267 }
268}