1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//! Complete render-session persistence for reproducible figures.
//!
//! Core scene manifests intentionally remain independent from GPU presentation
//! state. This envelope joins the scene description to the camera and ordered
//! render profile without copying caller-owned structure or volume data.
use super::RenderProfile;
use crate::error::RenderError;
use molgfx_core::{Scene, SceneDescription, SceneDescriptionSources};
use molgfx_math::Camera;
use serde::{Deserialize, Serialize};
/// A reproducible figure/session envelope.
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct RenderSession {
/// Schema version of this presentation envelope.
pub schema: u16,
/// Core scene composition and source fingerprints.
pub scene: SceneDescription,
/// Camera state used for the frame.
pub camera: Camera,
/// Ordered, weighted presentation modules.
pub profile: RenderProfile,
}
impl RenderSession {
/// Current session-envelope schema.
pub const SCHEMA: u16 = 1;
/// Captures scene composition without copying caller-owned source data.
#[must_use]
pub fn new(scene: &Scene, camera: Camera, profile: RenderProfile) -> Self {
Self {
schema: Self::SCHEMA,
scene: scene.describe(),
camera,
profile,
}
}
/// Encodes the complete session as stable pretty JSON.
///
/// # Errors
///
/// Returns [`RenderError::SessionEncoding`] when serialization fails.
pub fn to_json(&self) -> Result<String, RenderError> {
serde_json::to_string_pretty(self).map_err(|error| RenderError::SessionEncoding {
summary: error.to_string(),
})
}
/// Decodes and validates a session envelope without loading sources.
///
/// # Errors
///
/// Returns [`RenderError::SessionEncoding`] for malformed JSON or an
/// unsupported session schema.
pub fn from_json(source: &str) -> Result<Self, RenderError> {
let session: Self =
serde_json::from_str(source).map_err(|error| RenderError::SessionEncoding {
summary: error.to_string(),
})?;
if session.schema != Self::SCHEMA {
return Err(RenderError::SessionEncoding {
summary: format!(
"unsupported render session schema; expected {}",
Self::SCHEMA
),
});
}
Ok(session)
}
/// Rehydrates the core scene from the caller's source allocations.
///
/// # Errors
///
/// Returns the core validation error when a source fingerprint, handle or
/// scene-owned payload does not match the session.
pub fn restore(
&self,
sources: SceneDescriptionSources<'_>,
) -> Result<(Scene, Camera, RenderProfile), molgfx_core::CoreError> {
let scene = Scene::from_description(&self.scene, sources)?;
Ok((scene, self.camera, self.profile.clone()))
}
}
#[cfg(test)]
#[path = "session_tests.rs"]
mod tests;