battler_data/clauses/
rules.rs1use alloc::{
2 borrow::ToOwned,
3 string::String,
4};
5use core::{
6 fmt,
7 fmt::Display,
8 hash,
9 hash::Hash,
10 str::FromStr,
11};
12
13use anyhow::{
14 Error,
15 Result,
16};
17use hashbrown::HashSet;
18use serde_string_enum::{
19 DeserializeStringEnum,
20 SerializeStringEnum,
21};
22
23use crate::Id;
24
25#[derive(Debug, Clone, Eq, SerializeStringEnum, DeserializeStringEnum)]
27pub enum Rule {
28 Ban(Id),
30 Unban(Id),
36 Value { name: Id, value: String },
40 Repeal(Id),
44}
45
46impl Rule {
47 pub fn value_name(name: &str) -> Rule {
49 Rule::Value {
50 name: Id::from(name),
51 value: String::new(),
52 }
53 }
54
55 pub fn value_id(name: Id) -> Rule {
57 Rule::Value {
58 name: name,
59 value: String::new(),
60 }
61 }
62}
63
64impl Display for Rule {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 match self {
67 Self::Ban(id) => write!(f, "-{id}"),
68 Self::Unban(id) => write!(f, "+{id}"),
69 Self::Value { name, value } => {
70 if value.is_empty() {
71 write!(f, "{name}")
72 } else {
73 write!(f, "{name}={value}")
74 }
75 }
76 Self::Repeal(id) => write!(f, "!{id}"),
77 }
78 }
79}
80
81impl FromStr for Rule {
82 type Err = Error;
83 fn from_str(s: &str) -> Result<Self, Self::Err> {
84 match &s[0..1] {
85 "-" => Ok(Self::Ban(Id::from(s[1..].trim()))),
86 "+" => Ok(Self::Unban(Id::from(s[1..].trim()))),
87 "!" => Ok(Self::Repeal(Id::from(s[1..].trim()))),
88 _ => match s.split_once('=') {
89 None => Ok(Self::Value {
90 name: Id::from(s.trim()),
91 value: "".to_owned(),
92 }),
93 Some((name, value)) => Ok(Self::Value {
94 name: Id::from(name.trim()),
95 value: value.trim().to_owned(),
96 }),
97 },
98 }
99 }
100}
101
102impl Hash for Rule {
103 fn hash<H: hash::Hasher>(&self, state: &mut H) {
104 match self {
105 Self::Ban(id) => id.hash(state),
106 Self::Unban(id) => id.hash(state),
107 Self::Value { name, .. } => name.hash(state),
108 Self::Repeal(id) => id.hash(state),
109 }
110 }
111}
112
113impl PartialEq for Rule {
114 fn eq(&self, other: &Self) -> bool {
115 match self {
116 Self::Ban(id) => match other {
117 Self::Ban(other) => id.eq(other),
118 _ => false,
119 },
120 Self::Unban(id) => match other {
121 Self::Unban(other) => id.eq(other),
122 _ => false,
123 },
124 Self::Value { name, value: _ } => match other {
125 Self::Value {
126 name: other,
127 value: _,
128 } => name.eq(other),
129 _ => false,
130 },
131 Self::Repeal(id) => match other {
132 Self::Repeal(other) => id.eq(other),
133 _ => false,
134 },
135 }
136 }
137}
138
139pub type SerializedRuleSet = HashSet<Rule>;
141
142#[cfg(test)]
143mod rule_test {
144 use alloc::borrow::ToOwned;
145
146 use crate::{
147 Id,
148 Rule,
149 test_util::test_string_serialization,
150 };
151
152 #[test]
153 fn serializes_to_string() {
154 test_string_serialization(Rule::Ban(Id::from("bulbasaur")), "-bulbasaur");
155 test_string_serialization(Rule::Ban(Id::from("Giratina (Origin)")), "-giratinaorigin");
156 test_string_serialization(Rule::Unban(Id::from("Porygon-Z")), "+porygonz");
157 test_string_serialization(Rule::Repeal(Id::from("Evasion Clause")), "!evasionclause");
158 test_string_serialization(
159 Rule::Value {
160 name: Id::from("Max Level"),
161 value: "50".to_owned(),
162 },
163 "maxlevel=50",
164 );
165 }
166}