use std::fmt::{Display, Formatter};
use std::str::FromStr;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub const RUNTIME_PROTOCOL_VERSION: &str = "0.3";
pub const RUNTIME_PROTOCOL_CAPABILITIES: &[RuntimeCapability] = &[
RuntimeCapability::StructuredProtocolErrors,
RuntimeCapability::HeadlessStdioLogPaths,
RuntimeCapability::StatusSessionSetFilter,
RuntimeCapability::StatusUpdatedSinceFilter,
RuntimeCapability::TypedNudgeOutcomes,
RuntimeCapability::ValidateTargetPreflight,
RuntimeCapability::EventsCursor,
RuntimeCapability::EventsLongPoll,
RuntimeCapability::TmuxPaneSnapshot,
];
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct VersionInfo {
pub version: String,
pub git_sha: String,
pub protocol_version: String,
pub capabilities: Vec<RuntimeCapability>,
}
impl VersionInfo {
pub fn new(version: impl Into<String>, git_sha: impl Into<String>) -> Self {
Self {
version: version.into(),
git_sha: git_sha.into(),
protocol_version: RUNTIME_PROTOCOL_VERSION.to_owned(),
capabilities: RUNTIME_PROTOCOL_CAPABILITIES.to_vec(),
}
}
}
pub fn version_info() -> VersionInfo {
VersionInfo::new(env!("CARGO_PKG_VERSION"), env!("RTM_GIT_SHA"))
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RuntimeCapability {
StructuredProtocolErrors,
HeadlessStdioLogPaths,
StatusSessionSetFilter,
StatusUpdatedSinceFilter,
TypedNudgeOutcomes,
ValidateTargetPreflight,
EventsCursor,
EventsLongPoll,
TmuxPaneSnapshot,
}
impl RuntimeCapability {
pub const fn as_str(self) -> &'static str {
match self {
Self::StructuredProtocolErrors => "structured_protocol_errors",
Self::HeadlessStdioLogPaths => "headless_stdio_log_paths",
Self::StatusSessionSetFilter => "status_session_set_filter",
Self::StatusUpdatedSinceFilter => "status_updated_since_filter",
Self::TypedNudgeOutcomes => "typed_nudge_outcomes",
Self::ValidateTargetPreflight => "validate_target_preflight",
Self::EventsCursor => "events_cursor",
Self::EventsLongPoll => "events_long_poll",
Self::TmuxPaneSnapshot => "tmux_pane_snapshot",
}
}
}
impl Display for RuntimeCapability {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
formatter.write_str(self.as_str())
}
}
impl FromStr for RuntimeCapability {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"structured_protocol_errors" => Ok(Self::StructuredProtocolErrors),
"headless_stdio_log_paths" => Ok(Self::HeadlessStdioLogPaths),
"status_session_set_filter" => Ok(Self::StatusSessionSetFilter),
"status_updated_since_filter" => Ok(Self::StatusUpdatedSinceFilter),
"typed_nudge_outcomes" => Ok(Self::TypedNudgeOutcomes),
"validate_target_preflight" => Ok(Self::ValidateTargetPreflight),
"events_cursor" => Ok(Self::EventsCursor),
"events_long_poll" => Ok(Self::EventsLongPoll),
"tmux_pane_snapshot" => Ok(Self::TmuxPaneSnapshot),
other => Err(format!("unknown runtime capability {other}")),
}
}
}
impl Serialize for RuntimeCapability {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for RuntimeCapability {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
String::deserialize(deserializer)?
.parse()
.map_err(serde::de::Error::custom)
}
}