dia_semver/range/impls/
from_str.rs1use {
30 core::{
31 ops::Bound,
32 str::FromStr,
33 },
34 crate::{Error, Result, Range, Semver},
35};
36
37const MARK_SIZE: usize = 1;
39
40#[derive(Debug)]
41enum OpenMark {
42 Inclusive,
43 Exclusive,
44}
45
46impl OpenMark {
47
48 fn make_bound(self, semver: Option<Semver>) -> Result<Bound<Semver>> {
50 match semver {
51 None => match self {
52 OpenMark::Inclusive => Ok(Bound::Unbounded),
53 OpenMark::Exclusive => Err(err!("Start index of unbounded range must be inclusive")),
54 },
55 Some(semver) => match self {
56 OpenMark::Inclusive => Ok(Bound::Included(semver)),
57 OpenMark::Exclusive => Ok(Bound::Excluded(semver)),
58 },
59 }
60 }
61
62}
63
64#[derive(Debug)]
65enum CloseMark {
66 Inclusive,
67 Exclusive,
68}
69
70impl CloseMark {
71
72 fn make_bound(self, semver: Option<Semver>) -> Result<Bound<Semver>> {
74 match semver {
75 None => match self {
76 CloseMark::Inclusive => Ok(Bound::Unbounded),
77 CloseMark::Exclusive => Err(err!("End index of unbounded range must be inclusive")),
78 },
79 Some(semver) => match self {
80 CloseMark::Inclusive => Ok(Bound::Included(semver)),
81 CloseMark::Exclusive => Ok(Bound::Excluded(semver)),
82 },
83 }
84 }
85
86}
87
88#[test]
89fn test_mark() {
90 for c in &[
91 crate::range::INCLUSIVE_OPEN,
92 crate::range::INCLUSIVE_CLOSE,
93 crate::range::EXCLUSIVE_OPEN,
94 crate::range::EXCLUSIVE_CLOSE,
95 ] {
96 assert_eq!(c.len_utf8(), MARK_SIZE);
97 }
98}
99
100impl FromStr for Range {
101
102 type Err = Error;
103
104 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
105 #[cfg(target_pointer_width = "8")]
106 const MAX_LEN: usize = 255;
107
108 #[cfg(not(target_pointer_width = "8"))]
109 const MAX_LEN: usize = 4096;
110
111 if s.len() > MAX_LEN {
112 return Err(err!("String is too long, max length supported: {} bytes", MAX_LEN));
113 }
114
115 let err = || err!("Invalid range: {:?}", s);
116
117 let open_mark = match s.chars().next() {
118 Some(crate::range::INCLUSIVE_OPEN) => OpenMark::Inclusive,
119 Some(crate::range::EXCLUSIVE_OPEN) => OpenMark::Exclusive,
120 _ => return Err(err()),
121 };
122 let close_mark = if s.ends_with(crate::range::INCLUSIVE_CLOSE) {
123 CloseMark::Inclusive
124 } else if s.ends_with(crate::range::EXCLUSIVE_CLOSE) {
125 CloseMark::Exclusive
126 } else {
127 return Err(err());
128 };
129
130 let mut parts = s[MARK_SIZE .. s.len() - MARK_SIZE].trim().split(',').map(|s| s.trim());
131 let start = match parts.next() {
132 None => return Err(err()),
133 Some(start) => open_mark.make_bound(if start.is_empty() { None } else { Some(Semver::from_str(start).map_err(|_| err())?) })?,
134 };
135 let end = match parts.next() {
136 None => return Err(err()),
137 Some(end) => close_mark.make_bound(if end.is_empty() { None } else { Some(Semver::from_str(end).map_err(|_| err())?) })?,
138 };
139 if parts.next().is_none() {
140 Ok(Self { start, end })
141 } else {
142 Err(err())
143 }
144 }
145
146}