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