1use crate::{
2 AbstractDynamicDataType, AbstractMapDataType, AbstractValueDataType, DataVersion, JCompound,
3 JList, JValue, MapDataWalker,
4};
5use java_string::{JavaStr, JavaString};
6use log::warn;
7
8pub struct DataWalkerObjectListPaths<T>
9where
10 T: AbstractValueDataType,
11{
12 typ: T,
13 paths: Vec<String>,
14}
15
16impl<T> DataWalkerObjectListPaths<T>
17where
18 T: AbstractValueDataType,
19{
20 pub fn new(typ: T, path: impl Into<String>) -> Self {
21 Self::new_multi(typ, vec![path.into()])
22 }
23
24 pub fn new_multi(typ: T, paths: Vec<String>) -> Self {
25 Self { typ, paths }
26 }
27}
28
29impl<T> MapDataWalker for DataWalkerObjectListPaths<T>
30where
31 T: AbstractValueDataType,
32{
33 fn walk(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
34 for path in &self.paths {
35 convert_object_list_in_map(&self.typ, data, path, from_version, to_version);
36 }
37 }
38}
39
40pub struct DataWalkerMapListPaths<T>
41where
42 T: AbstractMapDataType,
43{
44 typ: T,
45 paths: Vec<String>,
46}
47
48impl<T> DataWalkerMapListPaths<T>
49where
50 T: AbstractMapDataType,
51{
52 pub fn new(typ: T, path: impl Into<String>) -> Self {
53 Self::new_multi(typ, vec![path.into()])
54 }
55
56 pub fn new_multi(typ: T, paths: Vec<String>) -> Self {
57 Self { typ, paths }
58 }
59}
60
61impl<T> MapDataWalker for DataWalkerMapListPaths<T>
62where
63 T: AbstractMapDataType,
64{
65 fn walk(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
66 for path in &self.paths {
67 convert_map_list_in_map(&self.typ, data, path, from_version, to_version);
68 }
69 }
70}
71
72pub struct DataWalkerDynamicListPaths<T>
73where
74 T: AbstractDynamicDataType,
75{
76 typ: T,
77 paths: Vec<String>,
78}
79
80impl<T> DataWalkerDynamicListPaths<T>
81where
82 T: AbstractDynamicDataType,
83{
84 pub fn new(typ: T, path: impl Into<String>) -> Self {
85 Self::new_multi(typ, vec![path.into()])
86 }
87
88 pub fn new_multi(typ: T, paths: Vec<String>) -> Self {
89 Self { typ, paths }
90 }
91}
92
93impl<T> MapDataWalker for DataWalkerDynamicListPaths<T>
94where
95 T: AbstractDynamicDataType,
96{
97 fn walk(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
98 for path in &self.paths {
99 convert_dynamic_list_in_map(&self.typ, data, path, from_version, to_version);
100 }
101 }
102}
103
104pub struct DataWalkerObjectTypePaths<T>
105where
106 T: AbstractValueDataType,
107{
108 typ: T,
109 paths: Vec<String>,
110}
111
112impl<T> DataWalkerObjectTypePaths<T>
113where
114 T: AbstractValueDataType,
115{
116 pub fn new(typ: T, path: impl Into<String>) -> Self {
117 Self::new_multi(typ, vec![path.into()])
118 }
119
120 pub fn new_multi(typ: T, paths: Vec<String>) -> Self {
121 Self { typ, paths }
122 }
123}
124
125impl<T> MapDataWalker for DataWalkerObjectTypePaths<T>
126where
127 T: AbstractValueDataType,
128{
129 fn walk(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
130 for path in &self.paths {
131 convert_object_in_map(&self.typ, data, path, from_version, to_version);
132 }
133 }
134}
135
136pub struct DataWalkerMapTypePaths<T>
137where
138 T: AbstractMapDataType,
139{
140 typ: T,
141 paths: Vec<String>,
142}
143
144impl<T> DataWalkerMapTypePaths<T>
145where
146 T: AbstractMapDataType,
147{
148 pub fn new(typ: T, path: impl Into<String>) -> Self {
149 Self::new_multi(typ, vec![path.into()])
150 }
151
152 pub fn new_multi(typ: T, paths: Vec<String>) -> Self {
153 Self { typ, paths }
154 }
155}
156
157impl<T> MapDataWalker for DataWalkerMapTypePaths<T>
158where
159 T: AbstractMapDataType,
160{
161 fn walk(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
162 for path in &self.paths {
163 convert_map_in_map(&self.typ, data, path, from_version, to_version);
164 }
165 }
166}
167
168pub struct DataWalkerDynamicTypePaths<T>
169where
170 T: AbstractDynamicDataType,
171{
172 typ: T,
173 paths: Vec<String>,
174}
175
176impl<T> DataWalkerDynamicTypePaths<T>
177where
178 T: AbstractDynamicDataType,
179{
180 pub fn new(typ: T, path: impl Into<String>) -> Self {
181 Self::new_multi(typ, vec![path.into()])
182 }
183
184 pub fn new_multi(typ: T, paths: Vec<String>) -> Self {
185 Self { typ, paths }
186 }
187}
188
189impl<T> MapDataWalker for DataWalkerDynamicTypePaths<T>
190where
191 T: AbstractDynamicDataType,
192{
193 fn walk(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
194 for path in &self.paths {
195 convert_dynamic_in_map(&self.typ, data, path, from_version, to_version);
196 }
197 }
198}
199
200pub fn convert_map_in_map<T>(
201 data_type: T,
202 data: &mut JCompound,
203 path: &(impl AsRef<JavaStr> + ?Sized),
204 from_version: DataVersion,
205 to_version: DataVersion,
206) where
207 T: AbstractMapDataType,
208{
209 if let Some(valence_nbt::Value::Compound(map)) = data.get_mut(path.as_ref()) {
210 data_type.convert(map, from_version, to_version);
211 }
212}
213
214pub fn convert_map_list_in_map<T>(
215 data_type: T,
216 data: &mut JCompound,
217 path: &(impl AsRef<JavaStr> + ?Sized),
218 from_version: DataVersion,
219 to_version: DataVersion,
220) where
221 T: AbstractMapDataType,
222{
223 if let Some(valence_nbt::Value::List(valence_nbt::List::Compound(list))) =
224 data.get_mut(path.as_ref())
225 {
226 for map in list {
227 data_type.convert(map, from_version, to_version);
228 }
229 }
230}
231
232pub fn convert_object_in_map<T>(
233 data_type: T,
234 data: &mut JCompound,
235 path: &(impl AsRef<JavaStr> + ?Sized),
236 from_version: DataVersion,
237 to_version: DataVersion,
238) where
239 T: AbstractValueDataType,
240{
241 if let Some(obj) = data.get_mut(path.as_ref()) {
242 data_type.convert(&mut obj.as_value_mut(), from_version, to_version);
243 }
244}
245
246pub fn convert_object_list<T>(
247 data_type: T,
248 data: &mut JList,
249 from_version: DataVersion,
250 to_version: DataVersion,
251) where
252 T: AbstractValueDataType,
253{
254 for mut obj in data.iter_mut() {
255 data_type.convert(&mut obj, from_version, to_version);
256 }
257}
258
259pub fn convert_object_list_in_map<T>(
260 data_type: T,
261 data: &mut JCompound,
262 path: &(impl AsRef<JavaStr> + ?Sized),
263 from_version: DataVersion,
264 to_version: DataVersion,
265) where
266 T: AbstractValueDataType,
267{
268 if let Some(valence_nbt::Value::List(list)) = data.get_mut(path.as_ref()) {
269 for mut obj in list.iter_mut() {
270 data_type.convert(&mut obj, from_version, to_version);
271 }
272 }
273}
274
275pub fn convert_dynamic_in_map<T>(
276 data_type: T,
277 data: &mut JCompound,
278 path: &(impl AsRef<JavaStr> + ?Sized),
279 from_version: DataVersion,
280 to_version: DataVersion,
281) where
282 T: AbstractDynamicDataType,
283{
284 if let Some(value) = data.get_mut(path.as_ref()) {
285 data_type.convert(value, from_version, to_version);
286 }
287}
288
289pub fn convert_dynamic_list_in_map<T>(
290 data_type: T,
291 data: &mut JCompound,
292 path: &(impl AsRef<JavaStr> + ?Sized),
293 from_version: DataVersion,
294 to_version: DataVersion,
295) where
296 T: AbstractDynamicDataType,
297{
298 fn convert_list_inner<T: AbstractDynamicDataType, E: Into<JValue>>(
299 data_type: T,
300 in_list: &mut Vec<E>,
301 from_version: DataVersion,
302 to_version: DataVersion,
303 ) -> JList {
304 let mut result = JList::new();
305 let mut all_success = true;
306 for element in in_list.drain(..) {
307 let mut element = element.into();
308 data_type.convert(&mut element, from_version, to_version);
309 all_success &= result.try_push(element)
310 }
311 if !all_success {
312 warn!("Result of list conversion was not homogenous");
313 }
314 result
315 }
316
317 let Some(valence_nbt::Value::List(list)) = data.get_mut(path.as_ref()) else {
318 return;
319 };
320 *list = match list {
321 valence_nbt::List::End => JList::End,
322 valence_nbt::List::Byte(bytes) => {
323 convert_list_inner(data_type, bytes, from_version, to_version)
324 }
325 valence_nbt::List::Short(shorts) => {
326 convert_list_inner(data_type, shorts, from_version, to_version)
327 }
328 valence_nbt::List::Int(ints) => {
329 convert_list_inner(data_type, ints, from_version, to_version)
330 }
331 valence_nbt::List::Long(longs) => {
332 convert_list_inner(data_type, longs, from_version, to_version)
333 }
334 valence_nbt::List::Float(floats) => {
335 convert_list_inner(data_type, floats, from_version, to_version)
336 }
337 valence_nbt::List::Double(doubles) => {
338 convert_list_inner(data_type, doubles, from_version, to_version)
339 }
340 valence_nbt::List::ByteArray(byte_arrays) => {
341 convert_list_inner(data_type, byte_arrays, from_version, to_version)
342 }
343 valence_nbt::List::String(strings) => {
344 convert_list_inner(data_type, strings, from_version, to_version)
345 }
346 valence_nbt::List::List(lists) => {
347 convert_list_inner(data_type, lists, from_version, to_version)
348 }
349 valence_nbt::List::Compound(compounds) => {
350 convert_list_inner(data_type, compounds, from_version, to_version)
351 }
352 valence_nbt::List::IntArray(int_arrays) => {
353 convert_list_inner(data_type, int_arrays, from_version, to_version)
354 }
355 valence_nbt::List::LongArray(long_arrays) => {
356 convert_list_inner(data_type, long_arrays, from_version, to_version)
357 }
358 }
359}
360
361pub fn convert_values_in_map<T>(
362 data_type: T,
363 data: &mut JCompound,
364 path: &(impl AsRef<JavaStr> + ?Sized),
365 from_version: DataVersion,
366 to_version: DataVersion,
367) where
368 T: AbstractMapDataType,
369{
370 if let Some(valence_nbt::Value::Compound(map)) = data.get_mut(path.as_ref()) {
371 convert_values(data_type, map, from_version, to_version);
372 }
373}
374
375pub fn convert_values<T>(
376 data_type: T,
377 data: &mut JCompound,
378 from_version: DataVersion,
379 to_version: DataVersion,
380) where
381 T: AbstractMapDataType,
382{
383 for obj in data.values_mut() {
384 if let valence_nbt::Value::Compound(map) = obj {
385 data_type.convert(map, from_version, to_version);
386 }
387 }
388}
389
390#[inline]
391pub fn rename_key(map: &mut JCompound, from: impl AsRef<JavaStr>, to: impl Into<JavaString>) {
392 if let Some(value) = map.remove(from.as_ref()) {
393 map.insert(to.into(), value);
394 }
395}
396
397pub fn rename_keys(map: &mut JCompound, renamer: impl Fn(&JavaStr) -> Option<JavaString>) {
398 let renames: Vec<_> = map
399 .keys()
400 .filter_map(|key| renamer(key).map(|new_key| (key.clone(), new_key)))
401 .collect();
402 let renamed: Vec<_> = renames
403 .into_iter()
404 .map(|(from, to)| (to, map.remove(&from[..]).unwrap()))
405 .collect();
406 for (key, value) in renamed {
407 map.insert(key, value);
408 }
409}
410
411pub fn get_mut_multi<'a, const N: usize>(
412 map: &'a mut JCompound,
413 keys: [&str; N],
414) -> [Option<&'a mut JValue>; N] {
415 #[cold]
416 #[inline(never)]
417 fn non_unique_keys(keys: &[&str]) -> ! {
418 panic!("keys are not all unique: {keys:?}")
419 }
420
421 if N > 1 {
422 for i in 0..N - 1 {
423 for j in i + 1..N {
424 if keys[i] == keys[j] {
425 non_unique_keys(&keys);
426 }
427 }
428 }
429 }
430
431 keys.map(|key| {
432 map.get_mut(key).map(|value| {
433 unsafe { &mut *(value as *mut _) }
435 })
436 })
437}