Skip to main content

bevy_convars/loader/
cvar_doc.rs

1use toml_edit::{ImDocument, Item, Table};
2
3use crate::{CVarFlags, CVarManagement, CVarTreeNode, reflect::ReflectCVar};
4
5pub(crate) type UnparsedCVar<'a> = (&'a str, Item);
6
7pub(crate) struct CVarDocScanner<S: AsRef<str>> {
8    document: ImDocument<S>,
9    source: String,
10}
11
12/// A toml document and it's associated source data
13#[derive(Clone)]
14pub struct DocumentContext<S: AsRef<str>> {
15    document: ImDocument<S>,
16    source: String,
17}
18
19impl Default for DocumentContext<String> {
20    fn default() -> Self {
21        Self {
22            document: ImDocument::parse(String::new()).unwrap(),
23            source: Default::default(),
24        }
25    }
26}
27
28impl<S: AsRef<str>> DocumentContext<S> {
29    /// Creates a new DocumentContext.
30    pub fn new(document: ImDocument<S>, source: String) -> Self {
31        Self { document, source }
32    }
33
34    /// Returns the source of this document.
35    pub fn source(&self) -> &str {
36        &self.source
37    }
38}
39
40impl<S: AsRef<str>> CVarDocScanner<S> {
41    pub fn new(document: DocumentContext<S>) -> Self {
42        Self {
43            document: document.document,
44            source: document.source,
45        }
46    }
47
48    /// Recursively traverse a TOML document for CVars.
49    fn traverse(
50        &self,
51        item: &Table,
52        management: &CVarManagement,
53        tree: &CVarTreeNode,
54        outp: &mut Vec<UnparsedCVar<'_>>,
55    ) {
56        for (key, node) in tree.children().unwrap() {
57            // Check if the node key exists within the document we're traversing, and if so get the value.
58            println!("{key}");
59            if let Some((_, value)) = item.get_key_value(key) {
60                if node.is_leaf() {
61                    let CVarTreeNode::Leaf { name, reg } = node else {
62                        unreachable!()
63                    };
64
65                    let meta = management.resources[reg].data::<ReflectCVar>().unwrap();
66
67                    if meta.flags().contains(CVarFlags::SAVED) {
68                        outp.push((*name, value.clone()));
69                    } else {
70                        bevy_log::warn!(
71                            "Found cvar {name} in {}, but that CVar cannot be saved (and as such cannot be loaded.)",
72                            self.source
73                        );
74                    }
75                } else if let Some(item) = value.as_table() {
76                    self.traverse(item, management, node, outp);
77                } else {
78                    bevy_log::warn!(
79                        "When parsing {}, found a cvar-like key {key} that was expected to be a table. Was of type {}",
80                        self.source,
81                        value.type_name()
82                    );
83                }
84            }
85        }
86    }
87
88    pub fn find_cvars(&self, management: &CVarManagement) -> Vec<UnparsedCVar<'_>> {
89        let mut outp = vec![];
90
91        self.traverse(
92            self.document.as_table(),
93            management,
94            &management.tree,
95            &mut outp,
96        );
97
98        outp
99    }
100}