steel_utils/value_providers/
vertical_anchor.rs1use serde::{Deserialize, Deserializer, de::Error as _};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum VerticalAnchor {
7 Absolute(i32),
9 AboveBottom(i32),
11 BelowTop(i32),
13 RelativeToSeaLevel(i32),
15}
16
17impl VerticalAnchor {
18 #[must_use]
20 pub const fn resolve_y(self, min_y: i32, height: i32, sea_level: i32) -> i32 {
21 match self {
22 Self::Absolute(y) => y,
23 Self::AboveBottom(offset) => min_y + offset,
24 Self::BelowTop(offset) => min_y + height - 1 - offset,
25 Self::RelativeToSeaLevel(offset) => sea_level + offset,
26 }
27 }
28}
29
30impl<'de> Deserialize<'de> for VerticalAnchor {
31 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
32 #[derive(Deserialize)]
33 #[serde(deny_unknown_fields)]
34 struct Raw {
35 #[serde(default)]
36 absolute: Option<i32>,
37 #[serde(default)]
38 above_bottom: Option<i32>,
39 #[serde(default)]
40 below_top: Option<i32>,
41 #[serde(default)]
42 relative_to_sea_level: Option<i32>,
43 }
44 let raw = Raw::deserialize(d)?;
45 match (
46 raw.absolute,
47 raw.above_bottom,
48 raw.below_top,
49 raw.relative_to_sea_level,
50 ) {
51 (Some(y), None, None, None) => Ok(Self::Absolute(y)),
52 (None, Some(o), None, None) => Ok(Self::AboveBottom(o)),
53 (None, None, Some(o), None) => Ok(Self::BelowTop(o)),
54 (None, None, None, Some(o)) => Ok(Self::RelativeToSeaLevel(o)),
55 (None, None, None, None) => Err(D::Error::custom(
56 "VerticalAnchor requires exactly one of absolute/above_bottom/below_top/relative_to_sea_level",
57 )),
58 _ => Err(D::Error::custom(
59 "VerticalAnchor must have exactly one of absolute/above_bottom/below_top/relative_to_sea_level",
60 )),
61 }
62 }
63}