bevy_persistent/
format.rs

1//! A storage format.
2
3use crate::prelude::*;
4
5/// A storage format.
6#[derive(Clone, Copy, Debug, Eq, PartialEq, Reflect)]
7pub enum StorageFormat {
8    #[cfg(feature = "bincode")]
9    Bincode,
10    #[cfg(feature = "ini")]
11    Ini,
12    #[cfg(feature = "json")]
13    Json,
14    #[cfg(all(feature = "json", feature = "pretty"))]
15    JsonPretty,
16    #[cfg(feature = "ron")]
17    Ron,
18    #[cfg(all(feature = "ron", feature = "pretty"))]
19    RonPretty,
20    #[cfg(all(feature = "ron", feature = "pretty"))]
21    RonPrettyWithStructNames,
22    #[cfg(feature = "toml")]
23    Toml,
24    #[cfg(all(feature = "toml", feature = "pretty"))]
25    TomlPretty,
26    #[cfg(feature = "yaml")]
27    Yaml,
28}
29
30#[cfg(any(
31    feature = "bincode",
32    feature = "ini",
33    feature = "json",
34    feature = "ron",
35    feature = "toml",
36    feature = "yaml",
37))]
38impl StorageFormat {
39    /// Serializes a resource into bytes.
40    pub fn serialize<R: Serialize + DeserializeOwned>(
41        self,
42        name: &str,
43        resource: &R,
44    ) -> Result<Vec<u8>, PersistenceError> {
45        match self {
46            #[cfg(feature = "bincode")]
47            StorageFormat::Bincode => {
48                bincode::serialize(resource).map_err(|error| {
49                    log::error!("failed to serialize {} to Bincode\n\n{}", name, error);
50                    PersistenceError::BincodeSerialization(error)
51                })
52            },
53            #[cfg(feature = "ini")]
54            StorageFormat::Ini => {
55                serde_ini::to_string(resource)
56                    .map(|serialized_resource| serialized_resource.into_bytes())
57                    .map_err(|error| {
58                        log::error!("failed to serialize {} to INI\n\n{}", name, error);
59                        PersistenceError::IniSerialization(error)
60                    })
61            },
62            #[cfg(feature = "json")]
63            StorageFormat::Json => {
64                serde_json::to_string(resource)
65                    .map(|serialized_resource| serialized_resource.into_bytes())
66                    .map_err(|error| {
67                        log::error!("failed to serialize {} to JSON\n\n{}", name, error);
68                        PersistenceError::JsonSerialization(error)
69                    })
70            },
71            #[cfg(all(feature = "json", feature = "pretty"))]
72            StorageFormat::JsonPretty => {
73                serde_json::to_string_pretty(resource)
74                    .map(|serialized_resource| serialized_resource.into_bytes())
75                    .map_err(|error| {
76                        log::error!("failed to serialize {} to pretty JSON\n\n{}", name, error);
77                        PersistenceError::JsonSerialization(error)
78                    })
79            },
80            #[cfg(feature = "ron")]
81            StorageFormat::Ron => {
82                ron::to_string(resource)
83                    .map(|serialized_resource| serialized_resource.into_bytes())
84                    .map_err(|error| {
85                        log::error!("failed to serialize {} to RON\n\n{}", name, error);
86                        PersistenceError::RonSerialization(error)
87                    })
88            },
89            #[cfg(all(feature = "ron", feature = "pretty"))]
90            StorageFormat::RonPretty => {
91                use ron::ser::PrettyConfig;
92                ron::ser::to_string_pretty(resource, PrettyConfig::new().struct_names(false))
93                    .map(|serialized_resource| serialized_resource.into_bytes())
94                    .map_err(|error| {
95                        log::error!("failed to serialize {} to pretty RON\n\n{}", name, error);
96                        PersistenceError::RonSerialization(error)
97                    })
98            },
99            #[cfg(all(feature = "ron", feature = "pretty"))]
100            StorageFormat::RonPrettyWithStructNames => {
101                use ron::ser::PrettyConfig;
102                ron::ser::to_string_pretty(resource, PrettyConfig::new().struct_names(true))
103                    .map(|serialized_resource| serialized_resource.into_bytes())
104                    .map_err(|error| {
105                        log::error!(
106                            "failed to serialize {} to pretty RON with struct names\n\n{}",
107                            name,
108                            error,
109                        );
110                        PersistenceError::RonSerialization(error)
111                    })
112            },
113            #[cfg(feature = "toml")]
114            StorageFormat::Toml => {
115                toml::to_string(resource)
116                    .map(|serialized_resource| serialized_resource.into_bytes())
117                    .map_err(|error| {
118                        log::error!("failed to serialize {} to TOML\n\n{}", name, error);
119                        PersistenceError::TomlSerialization(error)
120                    })
121            },
122            #[cfg(all(feature = "toml", feature = "pretty"))]
123            StorageFormat::TomlPretty => {
124                toml::to_string(resource)
125                    .map(|serialized_resource| serialized_resource.into_bytes())
126                    .map_err(|error| {
127                        log::error!("failed to serialize {} to pretty TOML\n\n{}", name, error);
128                        PersistenceError::TomlSerialization(error)
129                    })
130            },
131            #[cfg(feature = "yaml")]
132            StorageFormat::Yaml => {
133                serde_yaml::to_string(resource)
134                    .map(|serialized_resource| serialized_resource.into_bytes())
135                    .map_err(|error| {
136                        log::error!("failed to serialize {} to YAML\n\n{}", name, error);
137                        PersistenceError::YamlSerialization(error)
138                    })
139            },
140        }
141    }
142
143    /// Deserializes a resource from bytes.
144    pub fn deserialize<R: Serialize + DeserializeOwned>(
145        self,
146        name: &str,
147        serialized_resource: &[u8],
148    ) -> Result<R, PersistenceError> {
149        #[cfg(feature = "bincode")]
150        #[allow(irrefutable_let_patterns)]
151        if let StorageFormat::Bincode = self {
152            return bincode::deserialize::<R>(serialized_resource).map_err(|error| {
153                log::error!("failed to parse {} as Bincode\n\n{}", name, error);
154                PersistenceError::BincodeDeserialization(error)
155            });
156        }
157
158        #[cfg(any(
159            feature = "ini",
160            feature = "json",
161            feature = "ron",
162            feature = "toml",
163            feature = "yaml"
164        ))]
165        let serialized_resource_str =
166            std::str::from_utf8(serialized_resource).map_err(|error| {
167                log::error!("failed to decode {} as UTF-8\n\n{}", name, error);
168                PersistenceError::Encoding(error)
169            })?;
170
171        match self {
172            #[cfg(feature = "bincode")]
173            StorageFormat::Bincode => unreachable!(),
174            #[cfg(feature = "ini")]
175            StorageFormat::Ini => {
176                serde_ini::from_str::<R>(serialized_resource_str).map_err(|error| {
177                    log::error!("failed to parse {} as INI\n\n{}", name, error);
178                    PersistenceError::IniDeserialization(error)
179                })
180            },
181            #[cfg(feature = "json")]
182            StorageFormat::Json => {
183                serde_json::from_str::<R>(serialized_resource_str).map_err(|error| {
184                    log::error!("failed to parse {} as JSON\n\n{}", name, error);
185                    PersistenceError::JsonDeserialization(error)
186                })
187            },
188            #[cfg(all(feature = "json", feature = "pretty"))]
189            StorageFormat::JsonPretty => {
190                serde_json::from_str::<R>(serialized_resource_str).map_err(|error| {
191                    log::error!("failed to parse {} as pretty JSON\n\n{}", name, error);
192                    PersistenceError::JsonDeserialization(error)
193                })
194            },
195            #[cfg(feature = "ron")]
196            StorageFormat::Ron => {
197                ron::from_str::<R>(serialized_resource_str).map_err(|error| {
198                    log::error!("failed to parse {} as RON\n\n{}", name, error);
199                    PersistenceError::RonDeserialization(error.into())
200                })
201            },
202            #[cfg(all(feature = "ron", feature = "pretty"))]
203            StorageFormat::RonPretty => {
204                ron::from_str::<R>(serialized_resource_str).map_err(|error| {
205                    log::error!("failed to parse {} as pretty RON\n\n{}", name, error);
206                    PersistenceError::RonDeserialization(error.into())
207                })
208            },
209            #[cfg(all(feature = "ron", feature = "pretty"))]
210            StorageFormat::RonPrettyWithStructNames => {
211                ron::from_str::<R>(serialized_resource_str).map_err(|error| {
212                    log::error!(
213                        "failed to parse {} as pretty RON with struct names\n\n{}",
214                        name,
215                        error,
216                    );
217                    PersistenceError::RonDeserialization(error.into())
218                })
219            },
220            #[cfg(feature = "toml")]
221            StorageFormat::Toml => {
222                toml::from_str::<R>(serialized_resource_str).map_err(|error| {
223                    log::error!("failed to parse {} as TOML\n\n{}", name, error);
224                    PersistenceError::TomlDeserialization(error)
225                })
226            },
227            #[cfg(all(feature = "toml", feature = "pretty"))]
228            StorageFormat::TomlPretty => {
229                toml::from_str::<R>(serialized_resource_str).map_err(|error| {
230                    log::error!("failed to parse {} as pretty TOML\n\n{}", name, error);
231                    PersistenceError::TomlDeserialization(error)
232                })
233            },
234            #[cfg(feature = "yaml")]
235            StorageFormat::Yaml => {
236                serde_yaml::from_str::<R>(serialized_resource_str).map_err(|error| {
237                    log::error!("failed to parse {} as YAML\n\n{}", name, error);
238                    PersistenceError::YamlDeserialization(error)
239                })
240            },
241        }
242    }
243}
244
245#[cfg(not(any(
246    feature = "bincode",
247    feature = "ini",
248    feature = "json",
249    feature = "ron",
250    feature = "toml",
251    feature = "yaml",
252)))]
253impl StorageFormat {
254    /// Serializes a resource into bytes.
255    pub fn serialize<R: Serialize + DeserializeOwned>(
256        self,
257        _name: &str,
258        _resource: &R,
259    ) -> Result<Vec<u8>, PersistenceError> {
260        unreachable!()
261    }
262
263    /// Deserializes a resource from bytes.
264    pub fn deserialize<R: Serialize + DeserializeOwned>(
265        self,
266        _name: &str,
267        _serialized_resource: &[u8],
268    ) -> Result<R, PersistenceError> {
269        unreachable!()
270    }
271}