1use crate::{JCompound, JValue, JValueMut};
2use java_string::{JavaStr, JavaString};
3use std::cmp::Ordering;
4use std::collections::BTreeMap;
5use std::rc::Rc;
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
8pub struct DataVersion {
9 version: u32,
10 step: u32,
11}
12
13impl DataVersion {
14 pub fn new(version: u32, step: u32) -> Self {
15 Self { version, step }
16 }
17
18 #[inline]
19 pub fn get_version(&self) -> u32 {
20 self.version
21 }
22
23 #[inline]
24 pub fn get_step(&self) -> u32 {
25 self.step
26 }
27}
28
29impl From<u32> for DataVersion {
30 fn from(value: u32) -> Self {
31 DataVersion::new(value, 0)
32 }
33}
34
35pub trait MapDataConverterFunc {
36 fn convert(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion);
37}
38
39pub fn map_data_converter_func<'a, F>(func: F) -> impl MapDataConverterFunc + 'a
40where
41 F: Fn(&mut JCompound, DataVersion, DataVersion) + 'a,
42{
43 struct DataConverterFuncImpl<F>(F);
44 impl<F> MapDataConverterFunc for DataConverterFuncImpl<F>
45 where
46 F: Fn(&mut JCompound, DataVersion, DataVersion),
47 {
48 fn convert(
49 &self,
50 data: &mut JCompound,
51 from_version: DataVersion,
52 to_version: DataVersion,
53 ) {
54 (self.0)(data, from_version, to_version)
55 }
56 }
57 DataConverterFuncImpl(func)
58}
59
60impl<T: MapDataConverterFunc + ?Sized> MapDataConverterFunc for &T {
61 fn convert(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
62 T::convert(self, data, from_version, to_version)
63 }
64}
65
66impl<T: MapDataConverterFunc + ?Sized> MapDataConverterFunc for Box<T> {
67 fn convert(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
68 T::convert(self, data, from_version, to_version)
69 }
70}
71
72pub struct MapDataConverter<F: MapDataConverterFunc> {
73 to_version: DataVersion,
74 conversion_func: F,
75}
76
77impl<F: MapDataConverterFunc> MapDataConverter<F> {
78 pub fn new(to_version: impl Into<DataVersion>, conversion_func: F) -> Self {
79 Self {
80 to_version: to_version.into(),
81 conversion_func,
82 }
83 }
84
85 #[inline]
86 pub fn get_to_version(&self) -> DataVersion {
87 self.to_version
88 }
89
90 pub fn convert(
91 &self,
92 data: &mut JCompound,
93 from_version: impl Into<DataVersion>,
94 to_version: impl Into<DataVersion>,
95 ) {
96 self.conversion_func
97 .convert(data, from_version.into(), to_version.into())
98 }
99}
100
101pub trait ValueDataConverterFunc {
102 fn convert(&self, data: &mut JValueMut, from_version: DataVersion, to_version: DataVersion);
103}
104
105pub fn value_data_converter_func<'a, F>(func: F) -> impl ValueDataConverterFunc + 'a
106where
107 F: Fn(&mut JValueMut, DataVersion, DataVersion) + 'a,
108{
109 struct DataConverterFuncImpl<F>(F);
110 impl<F> ValueDataConverterFunc for DataConverterFuncImpl<F>
111 where
112 F: Fn(&mut JValueMut, DataVersion, DataVersion),
113 {
114 fn convert(
115 &self,
116 data: &mut JValueMut,
117 from_version: DataVersion,
118 to_version: DataVersion,
119 ) {
120 (self.0)(data, from_version, to_version)
121 }
122 }
123 DataConverterFuncImpl(func)
124}
125
126impl<T: ValueDataConverterFunc + ?Sized> ValueDataConverterFunc for &T {
127 fn convert(&self, data: &mut JValueMut, from_version: DataVersion, to_version: DataVersion) {
128 T::convert(self, data, from_version, to_version)
129 }
130}
131
132impl<T: ValueDataConverterFunc + ?Sized> ValueDataConverterFunc for Box<T> {
133 fn convert(&self, data: &mut JValueMut, from_version: DataVersion, to_version: DataVersion) {
134 T::convert(self, data, from_version, to_version)
135 }
136}
137
138pub struct ValueDataConverter<F: ValueDataConverterFunc> {
139 to_version: DataVersion,
140 conversion_func: F,
141}
142
143impl<F: ValueDataConverterFunc> ValueDataConverter<F> {
144 pub fn new(to_version: impl Into<DataVersion>, conversion_func: F) -> Self {
145 Self {
146 to_version: to_version.into(),
147 conversion_func,
148 }
149 }
150
151 #[inline]
152 pub fn get_to_version(&self) -> DataVersion {
153 self.to_version
154 }
155
156 pub fn convert(
157 &self,
158 data: &mut JValueMut,
159 from_version: impl Into<DataVersion>,
160 to_version: impl Into<DataVersion>,
161 ) {
162 self.conversion_func
163 .convert(data, from_version.into(), to_version.into())
164 }
165}
166
167pub trait DynamicDataConverterFunc {
168 fn convert(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion);
169}
170
171pub fn dynamic_data_converter_func<'a, F>(func: F) -> impl DynamicDataConverterFunc + 'a
172where
173 F: Fn(&mut JValue, DataVersion, DataVersion) + 'a,
174{
175 struct DataConverterFuncImpl<F>(F);
176 impl<F> DynamicDataConverterFunc for DataConverterFuncImpl<F>
177 where
178 F: Fn(&mut JValue, DataVersion, DataVersion),
179 {
180 fn convert(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion) {
181 (self.0)(data, from_version, to_version)
182 }
183 }
184 DataConverterFuncImpl(func)
185}
186
187impl<T: DynamicDataConverterFunc + ?Sized> DynamicDataConverterFunc for &T {
188 fn convert(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion) {
189 T::convert(self, data, from_version, to_version)
190 }
191}
192
193impl<T: DynamicDataConverterFunc + ?Sized> DynamicDataConverterFunc for Box<T> {
194 fn convert(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion) {
195 T::convert(self, data, from_version, to_version)
196 }
197}
198
199pub struct DynamicDataConverter<F: DynamicDataConverterFunc> {
200 to_version: DataVersion,
201 conversion_func: F,
202}
203
204impl<F: DynamicDataConverterFunc> DynamicDataConverter<F> {
205 pub fn new(to_version: impl Into<DataVersion>, conversion_func: F) -> Self {
206 Self {
207 to_version: to_version.into(),
208 conversion_func,
209 }
210 }
211
212 #[inline]
213 pub fn get_to_version(&self) -> DataVersion {
214 self.to_version
215 }
216
217 pub fn convert(
218 &self,
219 data: &mut JValue,
220 from_version: impl Into<DataVersion>,
221 to_version: impl Into<DataVersion>,
222 ) {
223 self.conversion_func
224 .convert(data, from_version.into(), to_version.into())
225 }
226}
227
228macro_rules! impl_traits {
229 ($converter:ident, $converter_func_trait:ident) => {
230 impl<F: $converter_func_trait> core::fmt::Debug for $converter<F> {
231 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result {
232 write!(
233 f,
234 concat!(stringify!($converter), "{{{:?}}}"),
235 self.to_version
236 )
237 }
238 }
239
240 impl<F: $converter_func_trait> PartialEq for $converter<F> {
241 fn eq(&self, other: &Self) -> bool {
242 self.to_version == other.to_version
243 }
244 }
245
246 impl<F: $converter_func_trait> Eq for $converter<F> {}
247
248 impl<F: $converter_func_trait> PartialOrd for $converter<F> {
249 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
250 Some(self.cmp(other))
251 }
252 }
253
254 impl<F: $converter_func_trait> Ord for $converter<F> {
255 fn cmp(&self, other: &Self) -> Ordering {
256 self.to_version.cmp(&other.to_version)
257 }
258 }
259 };
260}
261
262impl_traits!(MapDataConverter, MapDataConverterFunc);
263impl_traits!(ValueDataConverter, ValueDataConverterFunc);
264impl_traits!(DynamicDataConverter, DynamicDataConverterFunc);
265
266pub struct ConversionError {
267 pub message: String,
268}
269
270pub type Result<T> = core::result::Result<T, ConversionError>;
271
272pub trait AbstractMapDataType {
273 fn convert(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion);
274}
275
276impl<T: AbstractMapDataType> AbstractMapDataType for &T {
277 fn convert(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
278 T::convert(self, data, from_version, to_version)
279 }
280}
281
282impl<T: AbstractMapDataType> AbstractMapDataType for std::sync::RwLock<T> {
283 fn convert(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
284 let this = self.read().unwrap();
285 T::convert(&*this, data, from_version, to_version)
286 }
287}
288
289pub trait AbstractValueDataType {
290 fn convert(&self, data: &mut JValueMut, from_version: DataVersion, to_version: DataVersion);
291}
292
293impl<T: AbstractValueDataType> AbstractValueDataType for &T {
294 fn convert(&self, data: &mut JValueMut, from_version: DataVersion, to_version: DataVersion) {
295 T::convert(self, data, from_version, to_version)
296 }
297}
298
299impl<T: AbstractValueDataType> AbstractValueDataType for std::sync::RwLock<T> {
300 fn convert(&self, data: &mut JValueMut, from_version: DataVersion, to_version: DataVersion) {
301 let this = self.read().unwrap();
302 T::convert(&*this, data, from_version, to_version)
303 }
304}
305
306pub trait AbstractDynamicDataType {
307 fn convert(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion);
308}
309
310impl<T: AbstractDynamicDataType> AbstractDynamicDataType for &T {
311 fn convert(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion) {
312 T::convert(self, data, from_version, to_version)
313 }
314}
315
316impl<T: AbstractDynamicDataType> AbstractDynamicDataType for std::sync::RwLock<T> {
317 fn convert(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion) {
318 let this = self.read().unwrap();
319 T::convert(&*this, data, from_version, to_version)
320 }
321}
322
323macro_rules! structure_converters {
324 ($ty:ident, $field_name:ident, $data_converter:ident, $converter_func:ident) => {
325 impl<'a> $ty<'a> {
326 pub fn add_structure_converter(
327 &mut self,
328 version: impl Into<DataVersion>,
329 func: impl $converter_func + 'a,
330 ) {
331 let dyn_box: Box<dyn $converter_func> = Box::new(func);
332 let converter = $data_converter::new(version, dyn_box);
333 let index = self.$field_name.binary_search(&converter);
334 let index = match index {
335 Ok(i) => i,
336 Err(i) => i,
337 };
338 self.$field_name.insert(index, converter);
339 }
340 }
341 };
342}
343
344macro_rules! version_list {
345 ($ty:ident, $method_name:ident, $field_name:ident, $element_type:ty) => {
346 impl<'a> $ty<'a> {
347 pub fn $method_name(&mut self, version: impl Into<DataVersion>, value: $element_type) {
348 self.$field_name
349 .entry(version.into())
350 .or_default()
351 .push(Box::new(value));
352 }
353 }
354 };
355}
356
357type DynMapDataConverterFunc<'a> = Box<dyn MapDataConverterFunc + 'a>;
358
359pub struct MapDataType<'a> {
360 pub name: String,
361 structure_converters: Vec<MapDataConverter<DynMapDataConverterFunc<'a>>>,
362 structure_walkers: BTreeMap<DataVersion, Vec<Box<dyn MapDataWalker + 'a>>>,
363 structure_hooks: BTreeMap<DataVersion, Vec<Box<dyn MapDataHook + 'a>>>,
364}
365structure_converters!(
366 MapDataType,
367 structure_converters,
368 MapDataConverter,
369 MapDataConverterFunc
370);
371version_list!(
372 MapDataType,
373 add_structure_walker,
374 structure_walkers,
375 impl MapDataWalker + 'a
376);
377version_list!(
378 MapDataType,
379 add_structure_hook,
380 structure_hooks,
381 impl MapDataHook + 'a
382);
383impl<'a> MapDataType<'a> {
384 pub fn new(name: impl Into<String>) -> Self {
385 Self {
386 name: name.into(),
387 structure_converters: Vec::new(),
388 structure_walkers: BTreeMap::new(),
389 structure_hooks: BTreeMap::new(),
390 }
391 }
392}
393
394impl<'a> AbstractMapDataType for MapDataType<'a> {
395 fn convert(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
396 for converter in &self.structure_converters {
397 if converter.get_to_version() <= from_version {
398 continue;
399 }
400 if converter.get_to_version() > to_version {
401 break;
402 }
403
404 let hooks = self
405 .structure_hooks
406 .range(..=converter.get_to_version())
407 .next_back();
408 if let Some((_, hooks)) = hooks {
409 for hook in hooks {
410 hook.pre_hook(data, from_version, to_version);
411 }
412 }
413
414 converter.convert(data, from_version, to_version);
415
416 let hooks = self.structure_hooks.range(..=to_version).next_back();
418 if let Some((_, hooks)) = hooks {
419 for hook in hooks.iter().rev() {
420 hook.post_hook(data, from_version, to_version);
421 }
422 }
423 }
424
425 let hooks = self.structure_hooks.range(..=to_version).next_back();
426 if let Some((_, hooks)) = hooks {
427 for hook in hooks {
428 hook.pre_hook(data, from_version, to_version);
429 }
430 }
431
432 let walkers = self.structure_walkers.range(..=to_version).next_back();
433 if let Some((_, walkers)) = walkers {
434 for walker in walkers {
435 walker.walk(data, from_version, to_version);
436 }
437 }
438
439 if let Some((_, hooks)) = hooks {
440 for hook in hooks.iter().rev() {
441 hook.post_hook(data, from_version, to_version);
442 }
443 }
444 }
445}
446
447type DynValueDataConverterFunc<'a> = Box<dyn ValueDataConverterFunc + 'a>;
448
449pub struct ObjectDataType<'a> {
450 pub name: String,
451 converters: Vec<ValueDataConverter<DynValueDataConverterFunc<'a>>>,
452 structure_hooks: BTreeMap<DataVersion, Vec<Box<dyn ValueDataHook + 'a>>>,
453}
454structure_converters!(
455 ObjectDataType,
456 converters,
457 ValueDataConverter,
458 ValueDataConverterFunc
459);
460version_list!(
461 ObjectDataType,
462 add_structure_hook,
463 structure_hooks,
464 impl ValueDataHook + 'a
465);
466
467impl<'a> ObjectDataType<'a> {
468 pub fn new(name: impl Into<String>) -> Self {
469 Self {
470 name: name.into(),
471 converters: Vec::new(),
472 structure_hooks: BTreeMap::new(),
473 }
474 }
475}
476
477impl<'a> AbstractValueDataType for ObjectDataType<'a> {
478 fn convert(&self, data: &mut JValueMut, from_version: DataVersion, to_version: DataVersion) {
479 for converter in &self.converters {
480 if converter.get_to_version() <= from_version {
481 continue;
482 }
483 if converter.get_to_version() > to_version {
484 break;
485 }
486
487 let hooks = self
488 .structure_hooks
489 .range(..=converter.get_to_version())
490 .next_back();
491 if let Some((_, hooks)) = hooks {
492 for hook in hooks {
493 hook.pre_hook(data, from_version, to_version);
494 }
495 }
496
497 converter.convert(data, from_version, to_version);
498
499 let hooks = self.structure_hooks.range(..=to_version).next_back();
501 if let Some((_, hooks)) = hooks {
502 for hook in hooks.iter().rev() {
503 hook.post_hook(data, from_version, to_version);
504 }
505 }
506 }
507 }
508}
509
510type DynDynamicDataConverterFunc<'a> = Box<dyn DynamicDataConverterFunc + 'a>;
511
512pub struct DynamicDataType<'a> {
513 pub name: String,
514 structure_converters: Vec<DynamicDataConverter<DynDynamicDataConverterFunc<'a>>>,
515 structure_walkers: BTreeMap<DataVersion, Vec<Box<dyn DynamicDataWalker + 'a>>>,
516 structure_hooks: BTreeMap<DataVersion, Vec<Box<dyn DynamicDataHook + 'a>>>,
517}
518structure_converters!(
519 DynamicDataType,
520 structure_converters,
521 DynamicDataConverter,
522 DynamicDataConverterFunc
523);
524version_list!(
525 DynamicDataType,
526 add_structure_walker,
527 structure_walkers,
528 impl DynamicDataWalker + 'a
529);
530version_list!(
531 DynamicDataType,
532 add_structure_hook,
533 structure_hooks,
534 impl DynamicDataHook + 'a
535);
536
537impl<'a> DynamicDataType<'a> {
538 pub fn new(name: impl Into<String>) -> Self {
539 Self {
540 name: name.into(),
541 structure_converters: Vec::new(),
542 structure_walkers: BTreeMap::new(),
543 structure_hooks: BTreeMap::new(),
544 }
545 }
546}
547
548impl<'a> AbstractDynamicDataType for DynamicDataType<'a> {
549 fn convert(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion) {
550 for converter in &self.structure_converters {
551 if converter.get_to_version() <= from_version {
552 continue;
553 }
554 if converter.get_to_version() > to_version {
555 break;
556 }
557
558 let hooks = self
559 .structure_hooks
560 .range(..=converter.get_to_version())
561 .next_back();
562 if let Some((_, hooks)) = hooks {
563 for hook in hooks {
564 hook.pre_hook(data, from_version, to_version);
565 }
566 }
567
568 converter.convert(data, from_version, to_version);
569
570 let hooks = self.structure_hooks.range(..=to_version).next_back();
572 if let Some((_, hooks)) = hooks {
573 for hook in hooks.iter().rev() {
574 hook.post_hook(data, from_version, to_version);
575 }
576 }
577 }
578
579 let hooks = self.structure_hooks.range(..=to_version).next_back();
580 if let Some((_, hooks)) = hooks {
581 for hook in hooks {
582 hook.pre_hook(data, from_version, to_version);
583 }
584 }
585
586 let walkers = self.structure_walkers.range(..=to_version).next_back();
587 if let Some((_, walkers)) = walkers {
588 for walker in walkers {
589 walker.walk(data, from_version, to_version);
590 }
591 }
592
593 if let Some((_, hooks)) = hooks {
594 for hook in hooks.iter().rev() {
595 hook.post_hook(data, from_version, to_version);
596 }
597 }
598 }
599}
600
601type WalkersById<'a> = Vec<Rc<dyn MapDataWalker + 'a>>;
602
603pub struct IdDataType<'a> {
604 pub name: String,
605 structure_converters: Vec<MapDataConverter<DynMapDataConverterFunc<'a>>>,
606 structure_walkers: BTreeMap<DataVersion, Vec<Box<dyn MapDataWalker + 'a>>>,
607 structure_hooks: BTreeMap<DataVersion, Vec<Box<dyn MapDataHook + 'a>>>,
608 walkers_by_id: BTreeMap<JavaString, BTreeMap<DataVersion, WalkersById<'a>>>,
609}
610structure_converters!(
611 IdDataType,
612 structure_converters,
613 MapDataConverter,
614 MapDataConverterFunc
615);
616version_list!(
617 IdDataType,
618 add_structure_walker,
619 structure_walkers,
620 impl MapDataWalker + 'a
621);
622version_list!(
623 IdDataType,
624 add_structure_hook,
625 structure_hooks,
626 impl MapDataHook + 'a
627);
628
629impl<'a> IdDataType<'a> {
630 pub fn new(name: impl Into<String>) -> Self {
631 Self {
632 name: name.into(),
633 structure_converters: Vec::new(),
634 structure_walkers: BTreeMap::new(),
635 structure_hooks: BTreeMap::new(),
636 walkers_by_id: BTreeMap::new(),
637 }
638 }
639
640 pub fn add_converter_for_id(
641 &mut self,
642 id: impl Into<JavaString>,
643 version: impl Into<DataVersion>,
644 converter_func: impl MapDataConverterFunc + 'a,
645 ) {
646 let id_str = id.into();
647 self.add_structure_converter(
648 version,
649 map_data_converter_func(move |data, from_version, to_version| {
650 if matches!(data.get("id"), Some(valence_nbt::Value::String(str)) if str == &id_str)
651 {
652 converter_func.convert(data, from_version, to_version);
653 }
654 }),
655 );
656 }
657
658 pub fn add_walker_for_id(
659 &mut self,
660 version: impl Into<DataVersion>,
661 id: impl Into<JavaString>,
662 walker: impl MapDataWalker + 'a,
663 ) {
664 self.walkers_by_id
665 .entry(id.into())
666 .or_default()
667 .entry(version.into())
668 .or_default()
669 .push(Rc::new(walker));
670 }
671
672 pub fn copy_walkers(
673 &mut self,
674 version: impl Into<DataVersion> + Clone,
675 from_id: impl AsRef<JavaStr>,
676 to_id: impl Into<JavaString> + Clone,
677 ) {
678 if let Some(from_versions) = self.walkers_by_id.get(from_id.as_ref()) {
679 if let Some((_, from_walkers)) =
680 from_versions.range(..=version.clone().into()).next_back()
681 {
682 for walker in from_walkers.clone() {
683 self.walkers_by_id
684 .entry(to_id.clone().into())
685 .or_default()
686 .entry(version.clone().into())
687 .or_default()
688 .push(walker);
689 }
690 }
691 }
692 }
693}
694
695impl<'a> AbstractMapDataType for IdDataType<'a> {
696 fn convert(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
697 for converter in &self.structure_converters {
698 if converter.get_to_version() <= from_version {
699 continue;
700 }
701 if converter.get_to_version() > to_version {
702 break;
703 }
704
705 let hooks = self
706 .structure_hooks
707 .range(..=converter.get_to_version())
708 .next_back();
709 if let Some((_, hooks)) = hooks {
710 for hook in hooks {
711 hook.pre_hook(data, from_version, to_version);
712 }
713 }
714
715 converter.convert(data, from_version, to_version);
716
717 let hooks = self.structure_hooks.range(..=to_version).next_back();
719 if let Some((_, hooks)) = hooks {
720 for hook in hooks {
721 hook.post_hook(data, from_version, to_version);
722 }
723 }
724 }
725
726 let hooks = self.structure_hooks.range(..=to_version).next_back();
729 if let Some((_, hooks)) = hooks {
730 for hook in hooks.iter().rev() {
731 hook.pre_hook(data, from_version, to_version);
732 }
733 }
734
735 let walkers = self.structure_walkers.range(..=to_version).next_back();
738 if let Some((_, walkers)) = walkers {
739 for walker in walkers {
740 walker.walk(data, from_version, to_version);
741 }
742 }
743
744 if let Some(valence_nbt::Value::String(id)) = data.get("id") {
745 if let Some(walkers_by_version) = self.walkers_by_id.get(id) {
746 if let Some((_, walkers)) = walkers_by_version.range(..=to_version).next_back() {
747 for walker in walkers {
748 walker.walk(data, from_version, to_version);
749 }
750 }
751 }
752 }
753
754 if let Some((_, hooks)) = hooks {
757 for hook in hooks.iter().rev() {
758 hook.post_hook(data, from_version, to_version);
759 }
760 }
761 }
762}
763
764pub trait MapDataHook {
765 fn pre_hook(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion);
766 fn post_hook(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion);
767}
768
769pub trait ValueDataHook {
770 fn pre_hook(&self, data: &mut JValueMut, from_version: DataVersion, to_version: DataVersion);
771 fn post_hook(&self, data: &mut JValueMut, from_version: DataVersion, to_version: DataVersion);
772}
773
774pub trait DynamicDataHook {
775 fn pre_hook(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion);
776 fn post_hook(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion);
777}
778
779pub trait MapDataWalker {
780 fn walk(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion);
781}
782
783pub fn map_data_walker<'a, F>(func: F) -> impl MapDataWalker + 'a
784where
785 F: Fn(&mut JCompound, DataVersion, DataVersion) + 'a,
786{
787 struct MapDataWalkerImpl<F>(F);
788 impl<F> MapDataWalker for MapDataWalkerImpl<F>
789 where
790 F: Fn(&mut JCompound, DataVersion, DataVersion),
791 {
792 fn walk(&self, data: &mut JCompound, from_version: DataVersion, to_version: DataVersion) {
793 (self.0)(data, from_version, to_version)
794 }
795 }
796 MapDataWalkerImpl(func)
797}
798
799pub trait DynamicDataWalker {
800 fn walk(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion);
801}
802
803pub fn dynamic_data_walker<'a, F>(func: F) -> impl DynamicDataWalker + 'a
804where
805 F: Fn(&mut JValue, DataVersion, DataVersion) + 'a,
806{
807 struct DynamicDataWalkerImpl<F>(F);
808 impl<F> DynamicDataWalker for DynamicDataWalkerImpl<F>
809 where
810 F: Fn(&mut JValue, DataVersion, DataVersion),
811 {
812 fn walk(&self, data: &mut JValue, from_version: DataVersion, to_version: DataVersion) {
813 (self.0)(data, from_version, to_version)
814 }
815 }
816 DynamicDataWalkerImpl(func)
817}