dds_bridge/solver/
vulnerability.rs1use thiserror::Error;
4
5use core::fmt;
6use core::str::FromStr;
7
8bitflags::bitflags! {
9 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12 pub struct Vulnerability: u8 {
13 const NS = 1;
15 const EW = 2;
17 }
18}
19
20impl Vulnerability {
21 pub const ALL: Self = Self::all();
23
24 pub const NONE: Self = Self::empty();
26
27 #[must_use]
29 #[inline]
30 pub const fn to_sys(self) -> i32 {
31 const ALL: u8 = Vulnerability::all().bits();
32 const NS: u8 = Vulnerability::NS.bits();
33 const EW: u8 = Vulnerability::EW.bits();
34
35 match self.bits() {
36 0 => 0,
37 ALL => 1,
38 NS => 2,
39 EW => 3,
40 _ => unreachable!(),
41 }
42 }
43
44 #[must_use]
46 #[inline]
47 pub const fn rotate(self, condition: bool) -> Self {
48 Self::from_bits_truncate((self.bits() * 0x55) >> (condition as u8))
52 }
53}
54
55#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
57#[error("Invalid vulnerability: expected one of none, ns, ew, both")]
58pub struct ParseVulnerabilityError;
59
60impl FromStr for Vulnerability {
61 type Err = ParseVulnerabilityError;
62
63 fn from_str(s: &str) -> Result<Self, Self::Err> {
64 match s.to_ascii_lowercase().as_str() {
65 "none" => Ok(Self::NONE),
66 "ns" => Ok(Self::NS),
67 "ew" => Ok(Self::EW),
68 "both" | "all" => Ok(Self::ALL),
69 _ => Err(ParseVulnerabilityError),
70 }
71 }
72}
73
74impl fmt::Display for Vulnerability {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 f.write_str(match *self {
77 Self::NONE => "none",
78 Self::NS => "ns",
79 Self::EW => "ew",
80 Self::ALL => "both",
81 _ => unreachable!(),
82 })
83 }
84}
85
86const _: () = {
88 const ALL: Vulnerability = Vulnerability::all();
89 const NONE: Vulnerability = Vulnerability::empty();
90
91 assert!(matches!(ALL.rotate(true), ALL));
92 assert!(matches!(NONE.rotate(true), NONE));
93 assert!(matches!(Vulnerability::NS.rotate(true), Vulnerability::EW));
94 assert!(matches!(Vulnerability::EW.rotate(true), Vulnerability::NS));
95
96 assert!(matches!(ALL.rotate(false), ALL));
97 assert!(matches!(NONE.rotate(false), NONE));
98 assert!(matches!(Vulnerability::NS.rotate(false), Vulnerability::NS));
99 assert!(matches!(Vulnerability::EW.rotate(false), Vulnerability::EW));
100};