summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.rs1
-rw-r--r--src/persistence.rs77
-rw-r--r--src/playerstate.rs2
-rw-r--r--src/util.rs43
4 files changed, 121 insertions, 2 deletions
diff --git a/src/main.rs b/src/main.rs
index 92912c2..4301a07 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -27,6 +27,7 @@ mod savestate;
mod defaultencyclopedia;
mod playerstate;
mod playerid;
+mod persistence;
pub use self::pos::Pos;
pub use self::playerid::PlayerId;
diff --git a/src/persistence.rs b/src/persistence.rs
new file mode 100644
index 0000000..fc04378
--- /dev/null
+++ b/src/persistence.rs
@@ -0,0 +1,77 @@
+
+use std::path::PathBuf;
+use std::fs;
+use serde_json;
+use serde_json::Value;
+use crate::{
+ PlayerId,
+ savestate::SaveState,
+ playerstate::PlayerState,
+ util::Result,
+ aerr
+};
+
+pub trait PersistentStorage {
+
+ fn load_room(&self, name: String) -> Result<SaveState>;
+
+ fn load_player(&self, id: PlayerId) -> Result<PlayerState>;
+
+ fn save_room(&self, name: String, state: SaveState) -> Result<()>;
+
+ fn save_player(&self, id: PlayerId, sate: PlayerState) -> Result<()>;
+
+}
+
+
+pub struct FileStorage {
+ directory: PathBuf
+}
+
+impl PersistentStorage for FileStorage {
+
+ fn load_room(&self, name: String) -> Result<SaveState> {
+ let mut path = self.directory.clone();
+ path.push("rooms");
+ let fname = name + ".save.json";
+ path.push(fname);
+ let text = fs::read_to_string(path)?;
+ let json: Value = serde_json::from_str(&text)?;
+ SaveState::from_json(&json).ok_or(aerr!("not a valid save state"))
+ }
+
+ fn load_player(&self, id: PlayerId) -> Result<PlayerState> {
+ let mut path = self.directory.clone();
+ path.push("players");
+ let fname = id.name + ".save.json";
+ path.push(fname);
+ let text = fs::read_to_string(path)?;
+ let json: Value = serde_json::from_str(&text)?;
+ PlayerState::from_json(&json).ok_or(aerr!("not a valid save state"))
+ }
+
+ fn save_room(&self, name: String, state: SaveState) -> Result<()> {
+ let mut path = self.directory.clone();
+ path.push("rooms");
+ fs::create_dir_all(&path)?;
+ let fname = name + ".save.json";
+ path.push(fname);
+ let text = state.to_json().to_string();
+ // todo: write to a temp file first
+ fs::write(path, text)?;
+ Ok(())
+ }
+
+ fn save_player(&self, id: PlayerId, state: PlayerState) -> Result<()> {
+ let mut path = self.directory.clone();
+ path.push("players");
+ fs::create_dir_all(&path)?;
+ let fname = id.name + ".save.json";
+ path.push(fname);
+ let text = state.to_json().to_string();
+ // todo: write to a temp file first
+ fs::write(path, text)?;
+ Ok(())
+ }
+}
+
diff --git a/src/playerstate.rs b/src/playerstate.rs
index b9a7f1f..dac463b 100644
--- a/src/playerstate.rs
+++ b/src/playerstate.rs
@@ -43,7 +43,7 @@ impl PlayerState {
})
}
- pub fn from_json(val: Value) -> Option<Self> {
+ pub fn from_json(val: &Value) -> Option<Self> {
let inventory = val.get("inventory")?;
let mut items = vec![];
for item in inventory.get("items")?.as_array()? {
diff --git a/src/util.rs b/src/util.rs
index 34d5670..1aee8a4 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,5 +1,6 @@
-
+use std::error::Error;
+use std::fmt::{Display, Formatter};
use std::cmp::{min, max};
use serde_json::Value;
@@ -12,6 +13,46 @@ pub trait ToJson {
}
+pub type AnyError = Box<dyn Error + 'static>;
+pub type Result<T> = std::result::Result<T, AnyError>;
+
+#[derive(Debug)]
+pub struct AError {
+ text: String
+}
+
+impl AError {
+ pub fn new(txt: &str) -> Self{
+ AError {
+ text: txt.to_string()
+ }
+ }
+}
+
+impl Error for AError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ None
+ }
+}
+
+impl Display for AError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "Error: {}", self.text)
+ }
+}
+
+
+#[macro_export]
+macro_rules! aerr {
+ ($description:expr) => {Box::new(crate::util::AError::new($description))}
+}
+
+#[macro_export]
+macro_rules! err {
+ ($description:expr) => {Err(crate::aerr!($description))}
+}
+
+
#[macro_export]
macro_rules! hashmap {
( $($key:expr => $value:expr ),* ) => {{