1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::metadata::FieldVariant;
6use crate::metadata::MetadataStore;
7use crate::ObjectId;
8use crate::ObjectKind;
9use crate::parser::slk;
10use crate::ValueType;
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub enum Value {
14 String(String),
15 Int(i32),
16 Real(f32),
17 Unreal(f32),
18}
19
20impl Value {
21 pub fn default(type_id: u32) -> Option<Self> {
22 match type_id {
23 0 => Some(Value::Unreal(0.0)),
24 1 => Some(Value::Real(0.0)),
25 2 => Some(Value::Int(0)),
26 3 => Some(Value::String("".into())),
27 _ => None
28 }
29 }
30
31 pub fn from_str_and_ty(value: &str, ty: ValueType) -> Option<Self> {
32 Some(match ty {
33 ValueType::Unreal => Value::Unreal(value.parse().ok()?),
34 ValueType::Real => Value::Real(value.parse().ok()?),
35 ValueType::Int => Value::Int(value.parse().ok()?),
36 ValueType::String => Value::String(value.into()),
37 })
38 }
39
40 pub fn type_id(&self) -> u32 {
41 match self {
42 Value::Int(..) => 0,
43 Value::Real(..) => 1,
44 Value::Unreal(..) => 2,
45 Value::String(..) => 3,
46 }
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
51pub enum ValueKind {
52 Common,
53 SD,
54 HD,
55}
56
57#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58pub struct LeveledValue {
59 pub level: u32,
60 pub value: Option<Value>,
61 pub value_sd: Option<Value>,
62 pub value_hd: Option<Value>,
63}
64
65#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
66pub enum FieldKind {
67 Simple { value: Option<Value>, value_sd: Option<Value>, value_hd: Option<Value> },
68 Leveled { values: Vec<LeveledValue> },
69}
70
71#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
72pub struct Field {
73 pub id: ObjectId,
74 pub kind: FieldKind,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct Object {
79 kind: ObjectKind,
80 id: ObjectId,
81 aliased_id: Option<ObjectId>,
82 parent_id: Option<ObjectId>,
83 fields: BTreeMap<ObjectId, Field>,
84 dirty: bool,
85}
86
87impl Object {
88 pub fn new(id: ObjectId, kind: ObjectKind) -> Object {
89 Object {
90 id,
91 kind,
92 aliased_id: None,
93 parent_id: None,
94 fields: Default::default(),
95 dirty: true,
96 }
97 }
98
99 pub fn with_parent(id: ObjectId, parent_id: ObjectId, kind: ObjectKind) -> Object {
100 Object {
101 id,
102 kind,
103 aliased_id: None,
104 parent_id: Some(parent_id),
105 fields: Default::default(),
106 dirty: true,
107 }
108 }
109
110 pub fn id(&self) -> ObjectId {
111 self.id
112 }
113
114 pub fn set_id(&mut self, id: ObjectId) {
115 self.id = id
116 }
117
118 pub fn aliased_id(&self) -> Option<ObjectId> {
119 self.aliased_id
120 }
121
122 pub fn set_aliased_id(&mut self, aliased_id: Option<ObjectId>) {
123 self.aliased_id = aliased_id
124 }
125
126 pub fn parent_id(&self) -> Option<ObjectId> {
127 self.parent_id
128 }
129
130 pub fn set_parent_id(&mut self, parent_id: Option<ObjectId>) {
131 self.parent_id = parent_id
132 }
133
134 pub fn kind(&self) -> ObjectKind {
135 self.kind
136 }
137
138 pub fn is_dirty(&self) -> bool {
139 self.dirty
140 }
141
142 pub fn set_dirty(&mut self, dirty: bool) {
143 self.dirty = dirty
144 }
145
146 pub fn fields(&self) -> impl Iterator<Item=(&ObjectId, &Field)> {
147 self.fields.iter()
148 }
149
150 pub fn field(&self, id: ObjectId) -> Option<&Field> {
151 self.fields.get(&id)
152 }
153
154 pub fn simple_field(&self, id: ObjectId, value_kind: ValueKind) -> Option<&Value> {
155 self.fields.get(&id).and_then(|field| match &field.kind {
156 FieldKind::Simple { value, value_sd, value_hd } =>
157 match value_kind {
158 ValueKind::Common => value.as_ref(),
159 ValueKind::SD => value_sd.as_ref().or(value.as_ref()),
160 ValueKind::HD => value_hd.as_ref().or(value.as_ref()),
161 }
162 _ => None,
163 })
164 }
165
166 pub fn leveled_field(&self, id: ObjectId, level: u32, value_kind: ValueKind) -> Option<&Value> {
167 self.fields.get(&id).and_then(|field| match &field.kind {
168 FieldKind::Leveled { values } => values
169 .iter()
170 .find(|value| value.level == level)
171 .and_then(|value| match value_kind {
172 ValueKind::Common => value.value.as_ref(),
173 ValueKind::SD => value.value_sd.as_ref().or(value.value.as_ref()),
174 ValueKind::HD => value.value_hd.as_ref().or(value.value.as_ref())
175 }),
176 _ => None,
177 })
178 }
179
180 pub fn unset_simple_field(&mut self, id: ObjectId) {
181 self.dirty = true;
182
183 self.fields.remove(&id);
184 }
185
186 pub fn unset_leveled_field(&mut self, id: ObjectId, level: u32) {
187 self.dirty = true;
188
189 if let Some(field) = self.fields.get_mut(&id) {
190 if let FieldKind::Leveled { values } = &mut field.kind {
191 values.retain(|dv| dv.level != level)
192 }
193 }
194 }
195
196 pub fn set_simple_field(&mut self, id: ObjectId, value: Value, value_kind: ValueKind) {
197 self.dirty = true;
198
199 let field = self.fields.entry(id).or_insert_with(|| Field {
200 id,
201 kind: FieldKind::Simple {
202 value: None,
203 value_sd: None,
204 value_hd: None,
205 },
206 });
207
208 match &mut field.kind {
209 FieldKind::Simple { value: value_ref, value_sd: value_sd_ref, value_hd: value_hd_ref } => {
210 match value_kind {
211 ValueKind::Common => value_ref,
212 ValueKind::SD => value_sd_ref,
213 ValueKind::HD => value_hd_ref
214 }.replace(value);
215 },
216 FieldKind::Leveled { .. } => eprintln!(
217 "tried to insert simple field {} for object {}, but a data field {} already exists",
218 id, self.id, field.id
219 ),
220 }
221 }
222
223 pub fn set_leveled_field(&mut self, id: ObjectId, level: u32, value: Value, value_kind: ValueKind) {
224 self.dirty = true;
225
226 let field = self.fields.entry(id).or_insert_with(|| Field {
227 id,
228 kind: FieldKind::Leveled {
229 values: Default::default(),
230 },
231 });
232
233 match &mut field.kind {
234 FieldKind::Simple { .. } => eprintln!(
235 "tried to insert data field {} for object {}, but a simple field {} already exists",
236 id, self.id, field.id
237 ),
238 FieldKind::Leveled { values } => {
239 if let Some(leveled_value) = values.iter_mut().find(|dv| dv.level == level) {
240 match value_kind {
241 ValueKind::Common => leveled_value.value = Some(value),
242 ValueKind::SD => leveled_value.value_sd = Some(value),
243 ValueKind::HD => leveled_value.value_hd = Some(value)
244 }
245 } else {
246 values.push(
247 LeveledValue {
248 level,
249 value: if value_kind == ValueKind::Common {
250 Some(value.clone())
251 } else {
252 None
253 },
254 value_sd: if value_kind == ValueKind::SD {
255 Some(value.clone())
256 } else {
257 None
258 },
259 value_hd: if value_kind == ValueKind::HD {
260 Some(value.clone())
261 } else {
262 None
263 }
264 }
265 );
266 }
267 }
268 }
269 }
270
271 pub fn add_from(&mut self, other: &Object) {
276 self.dirty = true;
277
278 for (id, field) in &other.fields {
279 self.fields.insert(*id, field.clone());
280 }
281 }
282
283 pub(crate) fn process_slk_field(
284 &mut self,
285 value: &slk::Value,
286 name: &str,
287 metadata: &MetadataStore,
288 ) -> Option<()> {
289 let (field_meta, level) = metadata.query_slk_field(name, &self)?;
290
291 let value = Value::from_str_and_ty(value.as_inner()?, field_meta.value_ty)?;
292 let field_id = field_meta.id;
293
294 match field_meta.variant {
295 FieldVariant::Normal { .. } => self.set_simple_field(field_id, value, ValueKind::Common),
296 FieldVariant::Leveled { .. } | FieldVariant::Data { .. } => self.set_leveled_field(
297 field_id,
298 level.expect("field must have level specified"),
299 value,
300 ValueKind::Common,
301 ),
302 }
303
304 Some(())
305 }
306
307 pub(crate) fn process_func_field(
308 &mut self,
309 key: &str,
310 value: &str,
311 index: i8,
312 metadata: &MetadataStore,
313 ) -> Option<()> {
314 let hd = key.ends_with(":hd");
315 let value_kind = if hd { ValueKind::HD } else { ValueKind::Common };
316 let field_name = key.strip_suffix(":hd").unwrap_or(key);
317 let (field_meta, level) = metadata.query_profile_field(field_name, &self, index)?;
318 let value = Value::from_str_and_ty(value, field_meta.value_ty)?;
319
320 if let Some(level) = level {
321 self.set_leveled_field(field_meta.id, level, value, value_kind)
322 } else {
323 self.set_simple_field(field_meta.id, value, value_kind)
324 }
325
326 Some(())
327 }
328}