Skip to main content

openmw_config/config/
filesetting.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright (c) 2025 Dave Corley (S3kshun8)
3
4use crate::{GameSetting, GameSettingMeta};
5use std::fmt;
6
7/// A plain filename entry from an `openmw.cfg` file (`content=`, `fallback-archive=`, `groundcover=`).
8///
9/// Stores only the filename string — no path resolution is applied, since these entries name
10/// files looked up through the VFS rather than direct filesystem paths.
11///
12/// `PartialEq` comparisons are value-only and ignore source metadata, making it straightforward
13/// to check whether a particular file is present regardless of which config file defined it.
14#[derive(Debug, Clone)]
15pub struct FileSetting {
16    meta: GameSettingMeta,
17    value: String,
18}
19
20impl PartialEq for FileSetting {
21    fn eq(&self, other: &Self) -> bool {
22        &self.value == other.value()
23    }
24}
25
26impl PartialEq<&str> for FileSetting {
27    fn eq(&self, other: &&str) -> bool {
28        self.value == *other
29    }
30}
31
32impl PartialEq<str> for FileSetting {
33    fn eq(&self, other: &str) -> bool {
34        self.value == other
35    }
36}
37
38impl PartialEq<&String> for FileSetting {
39    fn eq(&self, other: &&String) -> bool {
40        &self.value == *other
41    }
42}
43
44impl GameSetting for FileSetting {
45    fn meta(&self) -> &GameSettingMeta {
46        &self.meta
47    }
48}
49
50impl fmt::Display for FileSetting {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        write!(f, "{}", self.value)
53    }
54}
55
56impl FileSetting {
57    /// Creates a new `FileSetting` attributed to `source_config`.
58    ///
59    /// Consumes the accumulated `comment` string (via [`std::mem::take`]).
60    pub fn new(value: &str, source_config: &std::path::Path, comment: &mut String) -> Self {
61        Self {
62            meta: GameSettingMeta {
63                source_config: source_config.to_path_buf(),
64                comment: std::mem::take(comment),
65            },
66            value: value.to_string(),
67        }
68    }
69
70    /// The filename string as it appeared in the `openmw.cfg` file.
71    #[must_use]
72    pub fn value(&self) -> &String {
73        &self.value
74    }
75
76    /// Borrowed string view of [`Self::value`].
77    #[must_use]
78    pub fn value_str(&self) -> &str {
79        &self.value
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use std::path::PathBuf;
87
88    #[test]
89    fn test_new_consumes_comment_and_sets_metadata() {
90        let source = PathBuf::from("/tmp/openmw.cfg");
91        let mut comment = String::from("# note\n");
92
93        let setting = FileSetting::new("Morrowind.esm", &source, &mut comment);
94
95        assert_eq!(setting.value(), "Morrowind.esm");
96        assert_eq!(setting.value_str(), "Morrowind.esm");
97        assert_eq!(setting.meta().source_config, source);
98        assert_eq!(setting.meta().comment, "# note\n");
99        assert!(comment.is_empty());
100    }
101
102    #[test]
103    fn test_display_outputs_only_file_value() {
104        let source = PathBuf::from("/tmp/openmw.cfg");
105        let mut comment = String::new();
106        let setting = FileSetting::new("Tribunal.esm", &source, &mut comment);
107
108        assert_eq!(setting.to_string(), "Tribunal.esm");
109    }
110
111    #[test]
112    fn test_partial_eq_variants_compare_by_value_only() {
113        let source = PathBuf::from("/tmp/openmw.cfg");
114        let mut comment = String::from("# ignored\n");
115
116        let lhs = FileSetting::new("Bloodmoon.esm", &source, &mut comment);
117        let rhs = FileSetting::new("Bloodmoon.esm", &source, &mut String::new());
118        let str_owned = String::from("Bloodmoon.esm");
119
120        assert_eq!(lhs, rhs);
121        assert_eq!(lhs, "Bloodmoon.esm");
122        assert_eq!(lhs, str_owned.as_str());
123        assert_eq!(lhs, &str_owned);
124    }
125}