Radish alpha
r
rad:z39mP9rQAaGmERfUMPULfPUi473tY
Radicle terminal user interface
Radicle
Git
feat(bin): Add state (de)serialization module
Erik Kundt committed 1 year ago
commit 3ab0da05d5c4ecb235270cfdd17a9d7f50fd66f5
parent 6a2ee67
4 files changed +107 -0
modified Cargo.lock
@@ -1300,6 +1300,12 @@ dependencies = [
]

[[package]]
+
name = "md5"
+
version = "0.7.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
+

+
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2031,6 +2037,7 @@ dependencies = [
 "lexopt",
 "libc",
 "log",
+
 "md5",
 "nom",
 "predicates",
 "pretty_assertions",
modified Cargo.toml
@@ -38,6 +38,7 @@ radicle-cli = { version = "0.12.1" }
radicle-surf = { version = "0.22.0" }
radicle-signals = { version = "0.10.0" }
ratatui = { version = "0.29.0", default-features = false, features = ["all-widgets", "termion", "serde"] }
+
md5 = { version = "0.7.0" }
simple-logging = { version = "2.0.2" }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
modified bin/main.rs
@@ -3,6 +3,7 @@ mod commands;
mod git;
mod log;
mod settings;
+
mod state;
mod terminal;
#[cfg(test)]
mod test;
added bin/state.rs
@@ -0,0 +1,98 @@
+
use std::path::PathBuf;
+
use std::{fmt::Display, fs};
+

+
use anyhow::Result;
+

+
use homedir::my_home;
+

+
use serde::{Deserialize, Serialize};
+

+
use radicle::cob::ObjectId;
+
use radicle::identity::RepoId;
+

+
const PATH: &str = ".radicle-tui/states";
+

+
/// Converts bytes to a deserializable type.
+
pub fn from_json<'a, D>(bytes: &'a [u8]) -> Result<D>
+
where
+
    D: Deserialize<'a>,
+
{
+
    Ok(serde_json::from_slice(bytes)?)
+
}
+

+
/// Converts serializable type to bytes.
+
pub fn to_json<S>(state: S) -> Result<Vec<u8>>
+
where
+
    S: Serialize,
+
{
+
    Ok(serde_json::to_vec(&state)?)
+
}
+

+
/// Trait for state readers.
+
pub trait ReadState {
+
    fn read(&self) -> Result<Vec<u8>>;
+
}
+

+
/// Trait for state writers.
+
pub trait WriteState: ReadState {
+
    fn write(&self, bytes: &[u8]) -> Result<()>;
+
}
+

+
/// A state storage that reads from and writes to a file.
+
pub struct FileStore {
+
    path: PathBuf,
+
}
+

+
impl FileStore {
+
    pub fn new(filename: impl ToString) -> Result<Self> {
+
        let folder = match my_home()? {
+
            Some(home) => format!("{}/{}", home.to_string_lossy(), PATH),
+
            _ => anyhow::bail!("Failed to read home directory"),
+
        };
+
        let path = format!("{}/{}.json", folder, filename.to_string());
+

+
        fs::create_dir_all(folder.clone())?;
+

+
        Ok(Self {
+
            path: PathBuf::from(path),
+
        })
+
    }
+
}
+

+
impl ReadState for FileStore {
+
    fn read(&self) -> Result<Vec<u8>> {
+
        let path = PathBuf::from(&self.path);
+

+
        Ok(fs::read(path)?)
+
    }
+
}
+

+
impl WriteState for FileStore {
+
    fn write(&self, contents: &[u8]) -> Result<()> {
+
        let path = PathBuf::from(&self.path);
+

+
        Ok(fs::write(path, contents)?)
+
    }
+
}
+

+
pub struct FileIdentifier {
+
    id: String,
+
}
+

+
impl FileIdentifier {
+
    pub fn new(command: &str, operation: &str, rid: &RepoId, id: Option<&ObjectId>) -> Self {
+
        let id = match id {
+
            Some(id) => format!("{}-{}-{}-{}", command, operation, rid, id),
+
            _ => format!("{}-{}-{}", command, operation, rid),
+
        };
+
        let id = format!("{:x}", md5::compute(id));
+

+
        Self { id }
+
    }
+
}
+

+
impl Display for FileIdentifier {
+
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+
        write!(f, "{}", self.id)
+
    }
+
}