So far, my only option seems to be a custom deserializer:
struct PositionVisitor;
impl<'de> serde::de::Visitor<'de> for PositionVisitor {
type Value = Position;
fn expecting(
&self,
formatter: &mut std::fmt::Formatter,
) -> std::fmt::Result {
formatter.write_str("a position, being either a single item or a pair")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let variant = seq
.next_element::<String>()?
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
let deserialized = match &variant[..] {
"Trim" => {
Position::Trim(seq.next_element()?.ok_or_else(|| {
serde::de::Error::invalid_length(1, &self)
})?)
}
"Stretch" => Position::Stretch,
_ => {
return Err(serde::de::Error::custom(format!(
"unknown type {variant}"
)))
}
};
Ok(deserialized)
}
}
impl<'de> Deserialize<'de> for Position {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_tuple(2, PositionVisitor)
}
}