use serde::Deserialize;
use serde::Serialize;
use crate::error::CanddingError;
use crate::error::Result;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum PositionScheme {
Rotary,
Absolute,
}
impl PositionScheme {
pub fn name(self) -> &'static str {
match self {
PositionScheme::Rotary => "rotary",
PositionScheme::Absolute => "absolute",
}
}
#[doc(hidden)]
pub fn from_config(value: &str) -> Option<Self> {
[PositionScheme::Rotary, PositionScheme::Absolute]
.into_iter()
.find(|scheme| scheme.name() == value)
}
#[doc(hidden)]
pub fn resolve(declared: Option<Self>, config: Option<&str>) -> Result<Self> {
match declared {
Some(scheme) if config == Some(scheme.name()) => Ok(scheme),
_ => Err(CanddingError::PositionSchemeDisagreesWithConfig {
declared: declared.map_or("none", PositionScheme::name).to_string(),
config: config.unwrap_or("none").to_string(),
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn each_scheme_serializes_as_the_config_value_that_names_it() {
for scheme in [PositionScheme::Rotary, PositionScheme::Absolute] {
let json = serde_json::to_value(scheme).unwrap();
assert_eq!(json, serde_json::Value::String(scheme.name().to_string()));
assert_eq!(PositionScheme::from_config(scheme.name()), Some(scheme));
}
assert_eq!(PositionScheme::from_config("alibi"), None);
assert_eq!(PositionScheme::from_config("relative_key"), None);
}
#[test]
fn resolve_keeps_the_declared_scheme_when_the_config_names_it() {
for scheme in [PositionScheme::Rotary, PositionScheme::Absolute] {
assert_eq!(
PositionScheme::resolve(Some(scheme), Some(scheme.name())).unwrap(),
scheme
);
}
}
#[test]
fn resolve_refuses_a_disagreement_and_either_side_missing() {
for (declared, config, expected) in [
(
Some(PositionScheme::Absolute),
Some("rotary"),
("absolute", "rotary"),
),
(
Some(PositionScheme::Rotary),
Some("absolute"),
("rotary", "absolute"),
),
(None, Some("absolute"), ("none", "absolute")),
(Some(PositionScheme::Absolute), None, ("absolute", "none")),
(
Some(PositionScheme::Rotary),
Some("alibi"),
("rotary", "alibi"),
),
] {
match PositionScheme::resolve(declared, config) {
Err(CanddingError::PositionSchemeDisagreesWithConfig { declared, config }) => {
assert_eq!((declared.as_str(), config.as_str()), expected)
}
other => panic!("{declared:?} against {config:?}: {other:?}"),
}
}
}
}