1use std::fmt::{self, Display};
4
5use crate::constraint::{Operator, SingleConstraint};
6
7#[derive(Debug, Clone)]
9pub struct Interval {
10 start: SingleConstraint,
11 end: SingleConstraint,
12}
13
14impl Interval {
15 #[must_use]
17 pub const fn new(start: SingleConstraint, end: SingleConstraint) -> Self {
18 Self { start, end }
19 }
20
21 #[must_use]
23 pub const fn start(&self) -> &SingleConstraint {
24 &self.start
25 }
26
27 #[must_use]
29 pub const fn end(&self) -> &SingleConstraint {
30 &self.end
31 }
32
33 #[must_use]
35 pub fn from_zero() -> SingleConstraint {
36 SingleConstraint::new(Operator::Ge, "0.0.0.0-dev")
37 }
38
39 #[must_use]
41 pub fn until_positive_infinity() -> SingleConstraint {
42 SingleConstraint::new(Operator::Lt, "9223372036854775807.0.0.0")
44 }
45
46 #[must_use]
48 pub fn any() -> Self {
49 Self::new(Self::from_zero(), Self::until_positive_infinity())
50 }
51}
52
53#[derive(Debug, Clone, PartialEq, Eq)]
58pub struct BranchConstraint {
59 pub names: Vec<String>,
60 pub exclude: bool,
61}
62
63impl BranchConstraint {
64 #[must_use]
66 pub const fn new(names: Vec<String>, exclude: bool) -> Self {
67 Self { names, exclude }
68 }
69
70 #[must_use]
72 pub const fn any_dev() -> Self {
73 Self {
74 names: Vec::new(),
75 exclude: true,
76 }
77 }
78
79 #[must_use]
81 pub const fn no_dev() -> Self {
82 Self {
83 names: Vec::new(),
84 exclude: false,
85 }
86 }
87
88 #[must_use]
90 pub const fn matches_any(&self) -> bool {
91 self.exclude && self.names.is_empty()
92 }
93
94 #[must_use]
96 pub const fn matches_none(&self) -> bool {
97 !self.exclude && self.names.is_empty()
98 }
99}
100
101impl Default for BranchConstraint {
102 fn default() -> Self {
103 Self::no_dev()
104 }
105}
106
107#[derive(Debug, Clone)]
109pub struct IntervalResult {
110 pub numeric: Vec<Interval>,
111 pub branches: BranchConstraint,
112}
113
114impl IntervalResult {
115 #[must_use]
116 pub const fn new(numeric: Vec<Interval>, branches: BranchConstraint) -> Self {
117 Self { numeric, branches }
118 }
119
120 #[must_use]
122 pub const fn none() -> Self {
123 Self {
124 numeric: Vec::new(),
125 branches: BranchConstraint::no_dev(),
126 }
127 }
128
129 #[must_use]
131 pub fn any() -> Self {
132 Self {
133 numeric: vec![Interval::any()],
134 branches: BranchConstraint::any_dev(),
135 }
136 }
137
138 #[must_use]
140 pub const fn matches_something(&self) -> bool {
141 !self.numeric.is_empty() || self.branches.exclude || !self.branches.names.is_empty()
142 }
143}
144
145impl Default for IntervalResult {
146 fn default() -> Self {
147 Self::none()
148 }
149}
150
151impl Display for Interval {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 write!(f, "[{} - {}]", self.start, self.end)
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn test_interval_creation() {
163 let interval = Interval::new(
164 SingleConstraint::new(Operator::Ge, "1.0.0.0-dev"),
165 SingleConstraint::new(Operator::Lt, "2.0.0.0-dev"),
166 );
167 assert_eq!(interval.start().operator(), Operator::Ge);
168 assert_eq!(interval.end().operator(), Operator::Lt);
169 }
170
171 #[test]
172 fn test_branch_constraint() {
173 let any = BranchConstraint::any_dev();
174 assert!(any.matches_any());
175 assert!(!any.matches_none());
176
177 let none = BranchConstraint::no_dev();
178 assert!(none.matches_none());
179 assert!(!none.matches_any());
180 }
181}