Skip to main content

lilo_rm_core/
version.rs

1use std::fmt::{Display, Formatter};
2use std::str::FromStr;
3
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5
6pub const RUNTIME_PROTOCOL_VERSION: &str = "0.2";
7
8pub const RUNTIME_PROTOCOL_CAPABILITIES: &[RuntimeCapability] = &[
9    RuntimeCapability::StructuredProtocolErrors,
10    RuntimeCapability::HeadlessStdioLogPaths,
11    RuntimeCapability::StatusSessionSetFilter,
12    RuntimeCapability::StatusUpdatedSinceFilter,
13    RuntimeCapability::TypedNudgeOutcomes,
14    RuntimeCapability::ValidateTargetPreflight,
15];
16
17#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
18pub struct VersionInfo {
19    pub version: String,
20    pub git_sha: String,
21    pub protocol_version: String,
22    pub capabilities: Vec<RuntimeCapability>,
23}
24
25impl VersionInfo {
26    pub fn new(version: impl Into<String>, git_sha: impl Into<String>) -> Self {
27        Self {
28            version: version.into(),
29            git_sha: git_sha.into(),
30            protocol_version: RUNTIME_PROTOCOL_VERSION.to_owned(),
31            capabilities: RUNTIME_PROTOCOL_CAPABILITIES.to_vec(),
32        }
33    }
34}
35
36pub fn version_info() -> VersionInfo {
37    VersionInfo::new(env!("CARGO_PKG_VERSION"), env!("RTM_GIT_SHA"))
38}
39
40#[derive(Clone, Copy, Debug, Eq, PartialEq)]
41pub enum RuntimeCapability {
42    /// Error responses expose stable machine readable codes.
43    StructuredProtocolErrors,
44    /// Headless spawn responses include stdout and stderr log paths.
45    HeadlessStdioLogPaths,
46    /// Status requests accept a set of session ids.
47    StatusSessionSetFilter,
48    /// Status requests accept an updated time lower bound.
49    StatusUpdatedSinceFilter,
50    /// Nudge responses expose typed delivery outcomes.
51    TypedNudgeOutcomes,
52    /// ValidateTarget checks a target string without spawning.
53    ValidateTargetPreflight,
54}
55
56impl RuntimeCapability {
57    pub const fn as_str(self) -> &'static str {
58        match self {
59            Self::StructuredProtocolErrors => "structured_protocol_errors",
60            Self::HeadlessStdioLogPaths => "headless_stdio_log_paths",
61            Self::StatusSessionSetFilter => "status_session_set_filter",
62            Self::StatusUpdatedSinceFilter => "status_updated_since_filter",
63            Self::TypedNudgeOutcomes => "typed_nudge_outcomes",
64            Self::ValidateTargetPreflight => "validate_target_preflight",
65        }
66    }
67}
68
69impl Display for RuntimeCapability {
70    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
71        formatter.write_str(self.as_str())
72    }
73}
74
75impl FromStr for RuntimeCapability {
76    type Err = String;
77
78    fn from_str(value: &str) -> Result<Self, Self::Err> {
79        match value {
80            "structured_protocol_errors" => Ok(Self::StructuredProtocolErrors),
81            "headless_stdio_log_paths" => Ok(Self::HeadlessStdioLogPaths),
82            "status_session_set_filter" => Ok(Self::StatusSessionSetFilter),
83            "status_updated_since_filter" => Ok(Self::StatusUpdatedSinceFilter),
84            "typed_nudge_outcomes" => Ok(Self::TypedNudgeOutcomes),
85            "validate_target_preflight" => Ok(Self::ValidateTargetPreflight),
86            other => Err(format!("unknown runtime capability {other}")),
87        }
88    }
89}
90
91impl Serialize for RuntimeCapability {
92    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
93    where
94        S: Serializer,
95    {
96        serializer.serialize_str(self.as_str())
97    }
98}
99
100impl<'de> Deserialize<'de> for RuntimeCapability {
101    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
102    where
103        D: Deserializer<'de>,
104    {
105        String::deserialize(deserializer)?
106            .parse()
107            .map_err(serde::de::Error::custom)
108    }
109}