use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum DeploymentMode {
#[default]
SingleNode,
Cluster,
Cloudflare,
}
impl DeploymentMode {
pub fn coordinator(self) -> &'static str {
match self {
Self::SingleNode => "the process itself (in-process mutex)",
Self::Cluster => "the Raft leader",
Self::Cloudflare => "the Raft leader (cluster on CF Containers)",
}
}
pub fn needs_managed_deployment(self) -> bool {
matches!(self, Self::Cloudflare)
}
pub fn as_str(self) -> &'static str {
match self {
Self::SingleNode => "single-node",
Self::Cluster => "cluster",
Self::Cloudflare => "cloudflare",
}
}
}
impl std::fmt::Display for DeploymentMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl std::str::FromStr for DeploymentMode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"single-node" | "single" => Ok(Self::SingleNode),
"cluster" => Ok(Self::Cluster),
"cloudflare" | "cf" => Ok(Self::Cloudflare),
other => Err(format!(
"unknown deployment mode `{other}` (expected single-node | cluster | cloudflare)"
)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trips_through_str() {
for mode in [
DeploymentMode::SingleNode,
DeploymentMode::Cluster,
DeploymentMode::Cloudflare,
] {
assert_eq!(mode.as_str().parse::<DeploymentMode>().unwrap(), mode);
}
}
#[test]
fn default_is_single_node() {
assert_eq!(DeploymentMode::default(), DeploymentMode::SingleNode);
assert!(!DeploymentMode::default().needs_managed_deployment());
}
#[test]
fn only_cloudflare_needs_managed_deployment() {
assert!(!DeploymentMode::SingleNode.needs_managed_deployment());
assert!(!DeploymentMode::Cluster.needs_managed_deployment());
assert!(DeploymentMode::Cloudflare.needs_managed_deployment());
}
#[test]
fn rejects_unknown_mode() {
assert!("kubernetes".parse::<DeploymentMode>().is_err());
}
}