Crate preferences [−] [src]
Read and write user-specific application data
This crate allows Rust developers to store and retrieve user-local preferences and other application data in a flexible and platform-appropriate way.
Though it was originally inspired by Java's convenient
Preferences API,
this crate is more flexible; any type that implements
rustc-serialize
's Encodable
and Decodable
traits can be stored and retrieved as user data! Thankfully, implementing those traits is
trivial; just use #[derive(RustcEncodable, RustcDecodable)
.
Usage
For convenience, the type PreferencesMap<T>
is provided. (It's
actually just a std::collections::HashMap<String, T>
, where T
defaults to
String
). This mirrors the Java API, which models user data as an opaque key-value store. As
long as the map is instantiated over a type T
which is serializable and deserializable,
PreferencesTrait
will be implemented for your map instance.
This will allow you to seamlessly save and load user data with the save(..)
and load(..)
methods on PreferencesTrait
.
Roadmap
This crate aims to provide a convenient API for both stable and nightly Rust, which is why
it currently uses rustc-serialize
instead of the more recent
serde
library. In the distant future, when compiler plugins are stabilized
and serde
is available in stable Rust, this library will migrate to serde
. This will be
a breaking change (and will update the semantic version number accordingly so that your
builds don't break). At that point, updating should be dead simple; you'll just have to
replace #[derive(RustcEncodable, RustcDecodable)
with #[derive(Serialize, Deserialize)
,
and only if you store custom data types in your user data.
Basic example
extern crate preferences; use preferences::{PreferencesMap, PreferencesTrait}; fn main() { // Create a new preferences key-value map // (Under the hood: HashMap<String, String>) let mut faves: PreferencesMap<String> = PreferencesMap::new(); // Edit the preferences (std::collections::HashMap) faves.insert("color".into(), "blue".into()); faves.insert("programming language".into(), "Rust".into()); // Store the user's preferences let prefs_key = "preferences-rs/examples/faves"; faves.save(prefs_key); // ... Then do some stuff ... // Retrieve the user's preferences let mut loaded_faves = PreferencesMap::new(); let load_result = loaded_faves.load(prefs_key); assert!(load_result.is_ok()); assert_eq!(loaded_faves, faves); }
Using custom data types
extern crate rustc_serialize; extern crate preferences; use preferences::{PreferencesMap, PreferencesTrait}; #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] struct PlayerData { level: u32, health: f32, } fn main() { let player = PlayerData{level: 2, health: 0.75}; let prefs_key = "preferences-rs/examples/player"; player.save(prefs_key); let mut loaded_player = PlayerData{level: 0, health: 0.0}; let load_result = loaded_player.load(prefs_key); assert!(load_result.is_ok()); assert_eq!(loaded_player, player); }
Using custom data types with PreferencesMap
extern crate rustc_serialize; extern crate preferences; use preferences::{PreferencesMap, PreferencesTrait}; #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] struct Point(f32, f32); fn main() { let mut places = PreferencesMap::new(); places.insert("treasure".into(), Point(1.0, 1.0)); places.insert("home".into(), Point(-1.0, 6.6)); let prefs_key = "preferences-rs/examples/places"; places.save(prefs_key); let mut loaded_places = PreferencesMap::new(); let load_result = loaded_places.load(prefs_key); assert!(load_result.is_ok()); assert_eq!(loaded_places, places); }
Using custom data types with serializable containers
extern crate rustc_serialize; extern crate preferences; use preferences::{PreferencesMap, PreferencesTrait}; #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] struct Point(usize, usize); fn main() { let square = vec![ Point(0,0), Point(1,0), Point(1,1), Point(0,1), ]; let prefs_key = "preferences-rs/examples/square"; square.save(prefs_key); let mut loaded_square: Vec<Point> = Vec::new(); let load_result = loaded_square.load(prefs_key); assert!(load_result.is_ok()); assert_eq!(loaded_square, square); }
Under the hood
Data is written to flat files under the active user's home directory in a location specific to the operating system.
- Mac OS X:
~/Library/Application Support
- Other Unix/Linux:
$XDG_DATA_HOME
, defaulting to~/.local/share
if not set - Windows:
%APPDATA%
, defaulting to<std::env::home_dir()>\AppData\Roaming
if not set
The data is stored in JSON format. This has several advantages:
- Human-readable and self-describing
- More compact than e.g. XML
- Better adoption rates and language compatibility than e.g. TOML
- Not reliant on a consistent memory layout like e.g. binary
You could, of course, implement PreferencesTrait
yourself and store your user data in
whatever location and format that you wanted. But that would defeat the purpose of this
library. 😊
Enums
PreferencesError |
Error type representing the errors that can occur when saving or loading user data. |
Traits
PreferencesTrait |
Trait for types that can be saved & loaded as user data. |
Type Definitions
PreferencesMap |
Generic key-value store for user data. |