gestalt/lib.rs
1//! Cross-platform configuration and data saving between desktop and web
2//!
3//! On desktop, saving is backed by filesystem and APIs and uses the platform-specific data
4//! locations. On web, saving is backed by the LocalStorage browser API.
5//! As an end user, all you need to worry about is which `Location` you want to save to:
6//! - `Cache`, which is short-lived and may not persist between runs of the program
7//! - `Config`, for storing long-term configuration
8//! - `Data`, for storing long-term large data blobs.
9
10#![deny(
11 bare_trait_objects,
12 missing_docs,
13 unused_extern_crates,
14 unused_import_braces,
15 unused_qualifications
16)]
17
18use serde::{Deserialize, Serialize};
19
20mod error;
21pub use self::error::SaveError;
22
23pub use serde;
24
25/// Where the data should be written to and read from
26///
27/// On desktop this determines which folder the file should be placed in (adhering to the XDG
28/// desktop specification), and on web it determines which various web storage APIs it should use.
29#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
30pub enum Location {
31 /// Cache should be used for short-lived data
32 ///
33 /// Cached data has no lifetime guarantee, and should be expected to be cleared between runs of
34 /// the program. On web, it is guaranteed when the user leaves the application and returns that
35 /// the cache data will have been cleared.
36 Cache,
37 /// Config should store application behavior configs, and will be long-lived
38 Config,
39 /// Data will store application data, and will be long-lived
40 Data,
41}
42
43/// Save some arbitrary data to the given location using Serde
44///
45/// Different platforms may have different save locations: on the Web, data is saved in local
46/// storage, on the desktop, it is stored in some appropriate home-directory folder.
47///
48/// The appname should be some constant; this is used to name the file to place the data in on
49/// desktop platforms. The profile should allow different things to save for the same app, such as
50/// save for different players in a game.
51///
52/// The example shows how to round-trip some data. Note that for [load](fn.load.html) you must
53/// explicitly specify the type of the data; this is because the struct is not passed as a
54/// parameter to `load` so Rust cannot infer the type.
55///
56/// ```
57/// use gestalt::{Location, save, load};
58/// use serde::{Serialize, Deserialize};
59///
60/// #[derive(Serialize, Deserialize)]
61/// struct Player {
62/// name: String,
63/// score: u32
64/// }
65///
66/// let player1 = Player { name: "Bob".to_string(), score: 21 };
67/// save(Location::Cache, "mygame", "player1", &player1).expect("Could not save Player 1");
68///
69/// let player2 = Player { name: "Alice".to_string(), score: 200 };
70/// save(Location::Cache, "mygame", "player2", &player2).expect("Could not save Player 2");
71///
72/// // Now reload.
73/// let player1 = load::<Player>(Location::Cache, "mygame", "player1").expect("Could not load Player 1");
74/// let player2 = load::<Player>(Location::Cache, "mygame", "player2").expect("Could not load Player 2");
75/// ```
76pub fn save<T: Serialize>(
77 location: Location,
78 appname: &str,
79 profile: &str,
80 data: &T,
81) -> Result<(), SaveError> {
82 platform::save(location, appname, profile, data)
83}
84
85/// Save some raw bytes to the given profile
86///
87/// Different platforms may have different save locations: on the Web, data is saved in local
88/// storage, on the desktop, it is stored in some appropriate home-directory folder.
89///
90/// The appname should be some constant; this is used to name the file to place the data in on
91/// desktop platforms. The profile should allow different things to save for the same app, such as
92/// save for different players in a game.
93pub fn save_raw(
94 location: Location,
95 appname: &str,
96 profile: &str,
97 data: &[u8],
98) -> Result<(), SaveError> {
99 platform::save_raw(location, appname, profile, data)
100}
101
102/// Load some data from the given profile using Serde
103///
104/// Different platforms may have different save locations: on the Web, data is saved in local
105/// storage, on the desktop, it is stored in some appropriate home-directory folder.
106///
107/// See [save](fn.save.html) for an example of saving and then loading some data.
108pub fn load<T>(location: Location, appname: &str, profile: &str) -> Result<T, SaveError>
109where
110 for<'de> T: Deserialize<'de>,
111{
112 platform::load(location, appname, profile)
113}
114
115/// Load some raw bytes from the given profile
116///
117/// Different platforms may have different save locations: on the Web, data is saved in local
118/// storage, on the desktop, it is stored in some appropriate home-directory folder.
119pub fn load_raw(location: Location, appname: &str, profile: &str) -> Result<Vec<u8>, SaveError> {
120 platform::load_raw(location, appname, profile)
121}
122
123// Select which platform implementation to use based on provided features
124
125#[cfg(not(target_arch = "wasm32"))]
126#[path = "desktop.rs"]
127mod platform;
128
129#[cfg(target_arch = "wasm32")]
130#[path = "web.rs"]
131mod platform;