Struct StateBlob
pub struct StateBlob {
pub kind: String,
pub version: u32,
pub data: Value,
}Expand description
A typed, versioned piece of state persisted through storage.
This is the replacement for Optuna’s system_attrs junk drawer: sampler
and scheduler state is data,
not object innards. It is serializable, so it survives a process restart
and works across machines; it carries a kind and a version, so a
backend can refuse to hand a v1 blob to code expecting v2 instead of
deserializing garbage.
use atune_core::storage::StateBlob;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct RungTable { rungs: Vec<u64> }
let blob = StateBlob::encode("asha", 1, &RungTable { rungs: vec![1, 3, 9] }).unwrap();
assert!(blob.is("asha", 1));
assert_eq!(blob.decode::<RungTable>().unwrap().rungs, vec![1, 3, 9]);Fields§
§kind: StringWhat produced the blob ("tpe", "asha", …). Namespaces the payload
inside a Scope.
version: u32The payload’s schema version, owned by whoever wrote it.
data: ValueThe payload.
Implementations§
§impl StateBlob
impl StateBlob
pub fn new(kind: impl Into<String>, version: u32, data: Value) -> Self
pub fn new(kind: impl Into<String>, version: u32, data: Value) -> Self
Wraps an already-serialized payload.
pub fn encode<T>(
kind: impl Into<String>,
version: u32,
value: &T,
) -> Result<Self>
pub fn encode<T>( kind: impl Into<String>, version: u32, value: &T, ) -> Result<Self>
Serializes value into a blob.
A finite value encodes exactly as serde_json::to_value does. A
non-finite f32 or f64 anywhere in value’s serialization is
refused: JSON has no spelling for it, serde_json would write null,
and decode would then reject the blob. State that
must keep a NaN or ±inf encodes that field as a string itself, as
the crate’s SafeF64 does for replicate results.
use atune_core::error::Error;
use atune_core::storage::StateBlob;
let refused = StateBlob::encode("curve", 1, &vec![(1_u64, 0.5), (2, f64::NAN)]);
assert!(matches!(
refused,
Err(Error::Storage(message)) if message.contains("non-finite float at /1/1")
));§Errors
Error::Storage if the value holds a non-finite float, naming the
first one’s location as an RFC 6901 JSON Pointer ((root) for the value
itself), or if the value cannot otherwise be serialized. The check walks
value’s serialization once before the encoding walks it again, so a
Serialize implementation must emit the same floats on every call, as
every derived one does.
pub fn decode<T>(&self) -> Result<T>where
T: DeserializeOwned,
pub fn decode<T>(&self) -> Result<T>where
T: DeserializeOwned,
Deserializes the payload.
The caller is expected to have checked is first; a
blob written by a different producer will usually fail here rather than
silently decode.
§Errors
Error::Storage if the payload does
not match T.
pub fn ensure_schema(&self, kind: &str, version: u32, what: &str) -> Result<()>
pub fn ensure_schema(&self, kind: &str, version: u32, what: &str) -> Result<()>
Rejects restoring this blob into a reader that expects kind at
version.
The fallible form of is, for restore paths: a blob
written by another producer or at a schema version the reader does not
migrate is refused as incompatible persisted state rather than decoded.
what names the state being restored ("sampler state",
"scheduler state", …) and becomes the error’s param.
use atune_core::error::Error;
use atune_core::storage::StateBlob;
let blob = StateBlob::new("asha", 1, serde_json::json!({}));
blob.ensure_schema("asha", 1, "scheduler state")
.expect("matching state schema is valid");
assert!(matches!(
blob.ensure_schema("asha", 2, "scheduler state"),
Err(Error::Incompatible { param, .. }) if param == "scheduler state"
));§Errors
Error::Incompatible naming
what if the blob has another kind or schema version.
pub fn ensure_schema_compatible(&self, replacement: &Self) -> Result<()>
pub fn ensure_schema_compatible(&self, replacement: &Self) -> Result<()>
Rejects replacing this blob with a different kind or schema version.
Lifecycle backends call this while holding their owner/transaction fence. A typed writer may replace the payload, but it must not replace an incompatible canonical blob and thereby erase data it cannot read.
§Errors
Error::Incompatible if the
replacement has a different kind or schema version.