bevy_persistent/
builder.rs

1//! A builder for a persistent resource.
2
3use crate::prelude::*;
4
5/// A builder for a persistent resource.
6pub struct PersistentBuilder<R: Resource + Serialize + DeserializeOwned> {
7    pub(crate) name: Option<String>,
8    pub(crate) format: Option<StorageFormat>,
9    pub(crate) path: Option<PathBuf>,
10    pub(crate) loaded: bool,
11    pub(crate) default: Option<R>,
12    pub(crate) revertible: bool,
13    pub(crate) revert_to_default_on_deserialization_errors: bool,
14}
15
16impl<R: Resource + Serialize + DeserializeOwned> PersistentBuilder<R> {
17    /// Sets the name of the resource.
18    pub fn name(mut self, name: impl ToString) -> PersistentBuilder<R> {
19        self.name = Some(name.to_string());
20        self
21    }
22
23    /// Sets the storage format of the resource.
24    pub fn format(mut self, format: StorageFormat) -> PersistentBuilder<R> {
25        self.format = Some(format);
26        self
27    }
28
29    /// Sets the path of the resource.
30    pub fn path(mut self, path: impl Into<PathBuf>) -> PersistentBuilder<R> {
31        self.path = Some(path.into());
32        self
33    }
34
35    /// Sets the initial loaded status of the resource.
36    pub fn loaded(mut self, loaded: bool) -> PersistentBuilder<R> {
37        self.loaded = loaded;
38        self
39    }
40
41    /// Sets the initial unloaded status of the resource.
42    pub fn unloaded(mut self, unloaded: bool) -> PersistentBuilder<R> {
43        self.loaded = !unloaded;
44        self
45    }
46
47    /// Sets the default value of the resource.
48    pub fn default(mut self, resource: R) -> PersistentBuilder<R> {
49        self.default = Some(resource);
50        self
51    }
52
53    /// Sets whether the the resource can be reverted to default.
54    pub fn revertible(mut self, revertible: bool) -> PersistentBuilder<R> {
55        self.revertible = revertible;
56        self
57    }
58
59    /// Sets whether the the resource should be reverted to default on deserialization errors.
60    pub fn revert_to_default_on_deserialization_errors(
61        mut self,
62        revert_to_default_on_deserialization_errors: bool,
63    ) -> PersistentBuilder<R> {
64        self.revert_to_default_on_deserialization_errors =
65            revert_to_default_on_deserialization_errors;
66        self
67    }
68}
69
70impl<R: Resource + Serialize + DeserializeOwned> PersistentBuilder<R> {
71    /// Builds the persistent resource.
72    ///
73    /// # Panics
74    ///
75    /// Panics if `name`, `path`, `format` or `default` is not set.
76    #[cfg(any(
77        feature = "bincode",
78        feature = "ini",
79        feature = "json",
80        feature = "ron",
81        feature = "toml",
82        feature = "yaml",
83    ))]
84    pub fn build(self) -> Result<Persistent<R>, PersistenceError> {
85        if self.name.is_none() {
86            panic!("persistent resource name is not set");
87        }
88        if self.format.is_none() {
89            panic!("persistent resource format is not set");
90        }
91        if self.path.is_none() {
92            panic!("persistent resource path is not set");
93        }
94        if self.default.is_none() {
95            panic!("persistent resource default is not set");
96        }
97
98        let name = self.name.unwrap();
99        let format = self.format.unwrap();
100        let path = self.path.unwrap();
101        let loaded = self.loaded;
102        let default = self.default.unwrap();
103        let revertible = self.revertible;
104        let revert_to_default_on_deserialization_errors =
105            self.revert_to_default_on_deserialization_errors;
106
107        let storage = {
108            #[cfg(not(target_family = "wasm"))]
109            {
110                Storage::Filesystem { path: path.canonicalize().unwrap_or(path) }
111            }
112            #[cfg(target_family = "wasm")]
113            {
114                let separator = std::path::MAIN_SEPARATOR_STR;
115                let path = path.strip_prefix(separator).unwrap_or(&path);
116
117                if let Ok(Some(key)) = path.strip_prefix("local").map(|p| p.to_str()) {
118                    Storage::LocalStorage { key: key.to_owned() }
119                } else if let Ok(Some(key)) = path.strip_prefix("session").map(|p| p.to_str()) {
120                    Storage::SessionStorage { key: key.to_owned() }
121                } else {
122                    panic!(
123                        "persistent resource path should start with \
124                        \"local\" or \"session\" and be UTF-8 encoded \
125                        in WebAssembly but it's {path:?}",
126                    );
127                }
128            }
129        };
130
131        Persistent::new(
132            name,
133            format,
134            storage,
135            loaded,
136            default,
137            revertible,
138            revert_to_default_on_deserialization_errors,
139        )
140    }
141
142    #[cfg(not(any(
143        feature = "bincode",
144        feature = "ini",
145        feature = "json",
146        feature = "ron",
147        feature = "toml",
148        feature = "yaml",
149    )))]
150    pub fn build(self) -> Result<Persistent<R>, PersistenceError> {
151        unreachable!()
152    }
153}