Skip to main content

rpfm_extensions/diagnostics/
dependency.rs

1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2026 Ismael Gutiérrez González. All rights reserved.
3//
4// This file is part of the Rusted PackFile Manager (RPFM) project,
5// which can be found here: https://github.com/Frodo45127/rpfm.
6//
7// This file is licensed under the MIT license, which can be found here:
8// https://github.com/Frodo45127/rpfm/blob/master/LICENSE.
9//---------------------------------------------------------------------------//
10
11//! Module with the structs and functions specific for `Dependency` diagnostics.
12
13use getset::{Getters, MutGetters};
14use serde_derive::{Serialize, Deserialize};
15
16use std::{fmt, fmt::Display};
17
18use rpfm_lib::files::pack::RESERVED_NAME_DEPENDENCIES_MANAGER_V2;
19
20use crate::diagnostics::*;
21
22//-------------------------------------------------------------------------------//
23//                              Enums & Structs
24//-------------------------------------------------------------------------------//
25
26/// This struct contains the results of a Dependency diagnostic.
27#[derive(Debug, Clone, Getters, MutGetters, Serialize, Deserialize)]
28#[getset(get = "pub", get_mut = "pub")]
29pub struct DependencyDiagnostic {
30    path: String,
31    pack: String,
32    results: Vec<DependencyDiagnosticReport>
33}
34
35/// This struct defines an individual dependency diagnostic result.
36#[derive(Debug, Clone, Getters, MutGetters, Serialize, Deserialize)]
37#[getset(get = "pub", get_mut = "pub")]
38pub struct DependencyDiagnosticReport {
39
40    /// List of cells, in "row, column" format.
41    ///
42    /// If the full row or full column are affected, use -1.
43    cells_affected: Vec<(i32, i32)>,
44    report_type: DependencyDiagnosticReportType,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub enum DependencyDiagnosticReportType {
49    InvalidDependencyPackName(String)
50}
51
52//-------------------------------------------------------------------------------//
53//                             Implementations
54//-------------------------------------------------------------------------------//
55
56impl Default for DependencyDiagnostic {
57    fn default() -> Self {
58        Self {
59            path: RESERVED_NAME_DEPENDENCIES_MANAGER_V2.to_owned(),
60            pack: String::new(),
61            results: vec![],
62        }
63    }
64}
65
66impl DependencyDiagnosticReport {
67    pub fn new(report_type: DependencyDiagnosticReportType, cells_affected: &[(i32, i32)]) -> Self {
68        Self {
69            cells_affected: cells_affected.to_vec(),
70            report_type
71        }
72    }
73}
74
75impl DiagnosticReport for DependencyDiagnosticReport {
76    fn message(&self) -> String {
77        match &self.report_type {
78            DependencyDiagnosticReportType::InvalidDependencyPackName(pack_name) => format!("Invalid dependency Pack name: {pack_name}"),
79        }
80    }
81
82    fn level(&self) -> DiagnosticLevel {
83        match self.report_type {
84            DependencyDiagnosticReportType::InvalidDependencyPackName(_) => DiagnosticLevel::Error,
85        }
86    }
87}
88
89impl Display for DependencyDiagnosticReportType {
90    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91        Display::fmt(match self {
92            Self::InvalidDependencyPackName(_) => "InvalidPackName",
93        }, f)
94    }
95}
96
97impl DependencyDiagnostic {
98
99    /// This function takes care of checking for errors in the Dependency Manager.
100    pub fn check(packs: &BTreeMap<String, Pack>) -> Vec<DiagnosticType> {
101        let mut diagnostics = Vec::new();
102
103        for (key, pack) in packs.iter() {
104            let mut diagnostic = DependencyDiagnostic {
105                pack: key.to_owned(),
106                ..Default::default()
107            };
108
109            for (index, (_, dep_name)) in pack.dependencies().iter().enumerate() {
110
111                // TODO: Make it so this also checks if the PackFile actually exists,
112                if dep_name.is_empty() || !dep_name.ends_with(".pack") || dep_name.contains(' ') {
113                    let result = DependencyDiagnosticReport::new(DependencyDiagnosticReportType::InvalidDependencyPackName(dep_name.to_string()), &[(index as i32, 1)]);
114                    diagnostic.results_mut().push(result);
115                }
116            }
117
118            if !diagnostic.results().is_empty() {
119                diagnostics.push(DiagnosticType::Dependency(diagnostic));
120            }
121        }
122
123        diagnostics
124    }
125}