use serde::{de::DeserializeOwned, Serialize};
use serde_json::from_value;
use crate::{
serialize::Value,
Result,
__private::{abort, read_field, write_field},
error,
};
use super::storage_has_key;
pub(crate) mod private {
pub trait Sealed {}
}
pub trait Storeable: private::Sealed + Sized {
fn decode(base_key: u64) -> Self;
fn parse_value(value: Value, base_key: u64) -> Result<Self>;
fn commit(self, base_key: u64);
fn exists(base_key: u64) -> bool {
storage_has_key(base_key, 0)
}
}
pub trait State: Sized {
fn load() -> Result<Self>;
fn init(value: serde_json::Value) -> Result<Self>;
fn http_get(path: String) -> Result<Option<String>>;
fn commit(self);
fn symbols() -> &'static [(&'static str, u64)];
}
pub trait ToPayload: private::Sealed {
fn to_payload(&self, path: &str) -> Result<Option<String>>;
}
impl<T: Serialize + DeserializeOwned> private::Sealed for T {}
impl<T: Serialize + DeserializeOwned> Storeable for T {
fn decode(base_key: u64) -> Self {
match read_field(base_key, 0) {
Some(val) => val,
None => {
error!("Failed to decode stored value: Base-Key {base_key} not found !");
abort();
}
}
}
fn parse_value(value: Value, _base_key: u64) -> Result<Self> {
Ok(from_value(value)?)
}
fn commit(self, base_key: u64) {
write_field(base_key, 0, &self)
}
}
impl<T: Serialize + private::Sealed> ToPayload for T {
fn to_payload(&self, path: &str) -> Result<Option<String>> {
let value = serde_json::to_value(self)?;
if path.is_empty() {
match value {
Value::String(s) => return Ok(Some(s)),
other => return Ok(Some(other.to_string())),
}
}
let mut current = &value;
for seg in path
.split('/')
.flat_map(|s| if s.is_empty() { None } else { Some(s) })
{
current = match current.get(seg) {
Some(v) => v,
None => return Ok(None),
};
}
match current {
Value::String(s) => Ok(Some(s.clone())),
other => Ok(Some(other.to_string())),
}
}
}