1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Copyright (c) Mysten Labs, Inc.
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use std::{io::Write, path::PathBuf};

pub trait EnumOrderMap {
    fn order_to_variant_map() -> std::collections::BTreeMap<u64, String>;
}

pub fn check_enum_compat_order<T: EnumOrderMap>(snapshot_file: PathBuf) {
    let new_map = T::order_to_variant_map();

    if let Err(err) = std::fs::read_to_string(snapshot_file.clone()) {
        if err.kind() == std::io::ErrorKind::NotFound {
            // Create the file if not exists
            let mut file = std::fs::File::create(snapshot_file).unwrap();
            let content: String = serde_yaml::to_string(&new_map).unwrap();

            write!(file, "{}", content).unwrap();
            return;
        }
        panic!("Error reading file: {:?}: err {:?}", snapshot_file, err);
    }

    let existing_map: std::collections::BTreeMap<u64, String> =
        serde_yaml::from_str(&std::fs::read_to_string(snapshot_file.clone()).unwrap()).unwrap();

    // Check that the new map includes the existing map in order
    for (pos, val) in existing_map {
        match new_map.get(&pos) {
            None => {
                panic!(
                    "Enum variant {} has been removed. Not allowed: enum must be backward compatible.",
                    val
                );
            }
            Some(new_val) if new_val == &val => continue,
            Some(new_val) => {
                panic!(
                    "Enum variant {val} has been swapped with {new_val} at position {pos}. Not allowed: enum must be backward compatible."
                );
            }
        }
    }

    // Update the file
    let mut file = std::fs::File::create(snapshot_file).unwrap();
    let content: String = serde_yaml::to_string(&new_map).unwrap();

    write!(file, "{}", content).unwrap();
}