Skip to main content

lash_core/plugin/
snapshot.rs

1//! Plugin snapshot types: how plugins persist their protocol-specific state
2//! across session reloads.
3//!
4//! Split out of `plugin/mod.rs` purely for file size; `pub use` in
5//! `plugin/mod.rs` preserves the external path.
6
7use std::collections::BTreeMap;
8
9use serde::{Deserialize, Serialize};
10
11#[derive(Clone, Debug, Default, Serialize, Deserialize)]
12pub struct PluginSessionSnapshot {
13    #[serde(default)]
14    pub plugins: BTreeMap<String, PluginSnapshotEntry>,
15}
16
17#[derive(Clone, Debug, Serialize, Deserialize)]
18pub struct PluginSnapshotEntry {
19    pub meta: PluginSnapshotMeta,
20    #[serde(default)]
21    pub artifacts: Vec<PluginSnapshotArtifact>,
22}
23
24#[derive(Clone, Debug, Serialize, Deserialize)]
25pub struct PluginSnapshotMeta {
26    pub plugin_id: String,
27    pub plugin_version: String,
28    #[serde(default)]
29    pub revision: u64,
30    #[serde(default, skip_serializing_if = "Option::is_none")]
31    pub state: Option<serde_json::Value>,
32}
33
34#[derive(Clone, Debug, Serialize, Deserialize)]
35pub struct PluginSnapshotArtifact {
36    pub name: String,
37    pub data: Vec<u8>,
38}
39
40pub trait SnapshotWriter {
41    fn write_blob(&mut self, name: String, data: Vec<u8>);
42}
43
44pub trait SnapshotReader {
45    fn read_blob(&self, name: &str) -> Option<&[u8]>;
46}
47
48#[derive(Default)]
49pub(crate) struct InMemorySnapshotWriter {
50    artifacts: Vec<PluginSnapshotArtifact>,
51}
52
53impl InMemorySnapshotWriter {
54    pub(crate) fn finish(self) -> Vec<PluginSnapshotArtifact> {
55        self.artifacts
56    }
57}
58
59impl SnapshotWriter for InMemorySnapshotWriter {
60    fn write_blob(&mut self, name: String, data: Vec<u8>) {
61        self.artifacts.push(PluginSnapshotArtifact { name, data });
62    }
63}
64
65pub(crate) struct InMemorySnapshotReader<'a> {
66    pub(crate) entry: &'a PluginSnapshotEntry,
67}
68
69impl SnapshotReader for InMemorySnapshotReader<'_> {
70    fn read_blob(&self, name: &str) -> Option<&[u8]> {
71        self.entry
72            .artifacts
73            .iter()
74            .find(|artifact| artifact.name == name)
75            .map(|artifact| artifact.data.as_slice())
76    }
77}