Skip to content

Commit e580683

Browse files
committed
fix: Don't panic when getting number of values
I was tempted to remove the exact-size nature. Wouldn't be breaking since it only panics but decided to go ahead and do this for now. Fixes #3241
1 parent 5c829ff commit e580683

File tree

1 file changed

+68
-4
lines changed

1 file changed

+68
-4
lines changed

src/parse/matches/arg_matches.rs

+68-4
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ impl ArgMatches {
260260
}
261261
let v = Values {
262262
iter: arg.vals_flatten().map(to_str_slice),
263+
len: arg.num_vals(),
263264
};
264265
Some(v)
265266
}
@@ -274,6 +275,7 @@ impl ArgMatches {
274275
iter: arg
275276
.vals()
276277
.map(|g| g.iter().map(|x| x.to_str().expect(INVALID_UTF8)).collect()),
278+
len: arg.vals().len(),
277279
};
278280
Some(v)
279281
}
@@ -376,6 +378,7 @@ impl ArgMatches {
376378
}
377379
let v = OsValues {
378380
iter: arg.vals_flatten().map(to_str_slice),
381+
len: arg.num_vals(),
379382
};
380383
Some(v)
381384
}
@@ -863,6 +866,7 @@ impl ArgMatches {
863866
let arg = self.get_arg(&Id::from(id))?;
864867
let i = Indices {
865868
iter: arg.indices(),
869+
len: arg.num_vals(),
866870
};
867871
Some(i)
868872
}
@@ -1080,6 +1084,7 @@ pub(crate) struct SubCommand {
10801084
pub struct Values<'a> {
10811085
#[allow(clippy::type_complexity)]
10821086
iter: Map<Flatten<Iter<'a, Vec<OsString>>>, for<'r> fn(&'r OsString) -> &'r str>,
1087+
len: usize,
10831088
}
10841089

10851090
impl<'a> Iterator for Values<'a> {
@@ -1089,7 +1094,7 @@ impl<'a> Iterator for Values<'a> {
10891094
self.iter.next()
10901095
}
10911096
fn size_hint(&self) -> (usize, Option<usize>) {
1092-
self.iter.size_hint()
1097+
(self.len, Some(self.len))
10931098
}
10941099
}
10951100

@@ -1107,6 +1112,7 @@ impl<'a> Default for Values<'a> {
11071112
static EMPTY: [Vec<OsString>; 0] = [];
11081113
Values {
11091114
iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
1115+
len: 0,
11101116
}
11111117
}
11121118
}
@@ -1116,6 +1122,7 @@ impl<'a> Default for Values<'a> {
11161122
pub struct GroupedValues<'a> {
11171123
#[allow(clippy::type_complexity)]
11181124
iter: Map<Iter<'a, Vec<OsString>>, fn(&Vec<OsString>) -> Vec<&str>>,
1125+
len: usize,
11191126
}
11201127

11211128
impl<'a> Iterator for GroupedValues<'a> {
@@ -1125,7 +1132,7 @@ impl<'a> Iterator for GroupedValues<'a> {
11251132
self.iter.next()
11261133
}
11271134
fn size_hint(&self) -> (usize, Option<usize>) {
1128-
self.iter.size_hint()
1135+
(self.len, Some(self.len))
11291136
}
11301137
}
11311138

@@ -1143,6 +1150,7 @@ impl<'a> Default for GroupedValues<'a> {
11431150
static EMPTY: [Vec<OsString>; 0] = [];
11441151
GroupedValues {
11451152
iter: EMPTY[..].iter().map(|_| unreachable!()),
1153+
len: 0,
11461154
}
11471155
}
11481156
}
@@ -1171,6 +1179,7 @@ impl<'a> Default for GroupedValues<'a> {
11711179
pub struct OsValues<'a> {
11721180
#[allow(clippy::type_complexity)]
11731181
iter: Map<Flatten<Iter<'a, Vec<OsString>>>, fn(&OsString) -> &OsStr>,
1182+
len: usize,
11741183
}
11751184

11761185
impl<'a> Iterator for OsValues<'a> {
@@ -1180,7 +1189,7 @@ impl<'a> Iterator for OsValues<'a> {
11801189
self.iter.next()
11811190
}
11821191
fn size_hint(&self) -> (usize, Option<usize>) {
1183-
self.iter.size_hint()
1192+
(self.len, Some(self.len))
11841193
}
11851194
}
11861195

@@ -1198,6 +1207,7 @@ impl Default for OsValues<'_> {
11981207
static EMPTY: [Vec<OsString>; 0] = [];
11991208
OsValues {
12001209
iter: EMPTY[..].iter().flatten().map(|_| unreachable!()),
1210+
len: 0,
12011211
}
12021212
}
12031213
}
@@ -1226,6 +1236,7 @@ impl Default for OsValues<'_> {
12261236
#[allow(missing_debug_implementations)]
12271237
pub struct Indices<'a> {
12281238
iter: Cloned<Iter<'a, usize>>,
1239+
len: usize,
12291240
}
12301241

12311242
impl<'a> Iterator for Indices<'a> {
@@ -1235,7 +1246,7 @@ impl<'a> Iterator for Indices<'a> {
12351246
self.iter.next()
12361247
}
12371248
fn size_hint(&self) -> (usize, Option<usize>) {
1238-
self.iter.size_hint()
1249+
(self.len, Some(self.len))
12391250
}
12401251
}
12411252

@@ -1254,6 +1265,7 @@ impl<'a> Default for Indices<'a> {
12541265
// This is never called because the iterator is empty:
12551266
Indices {
12561267
iter: EMPTY[..].iter().cloned(),
1268+
len: 0,
12571269
}
12581270
}
12591271
}
@@ -1320,4 +1332,56 @@ mod tests {
13201332
let mut indices = matches.indices_of("").unwrap_or_default();
13211333
assert_eq!(indices.next(), None);
13221334
}
1335+
1336+
#[test]
1337+
fn values_exact_size() {
1338+
let l = crate::App::new("test")
1339+
.arg(
1340+
crate::Arg::new("POTATO")
1341+
.takes_value(true)
1342+
.multiple_values(true)
1343+
.required(true),
1344+
)
1345+
.try_get_matches_from(["test", "one"])
1346+
.unwrap()
1347+
.values_of("POTATO")
1348+
.expect("present")
1349+
.len();
1350+
assert_eq!(l, 1);
1351+
}
1352+
1353+
#[test]
1354+
fn os_values_exact_size() {
1355+
let l = crate::App::new("test")
1356+
.arg(
1357+
crate::Arg::new("POTATO")
1358+
.takes_value(true)
1359+
.multiple_values(true)
1360+
.allow_invalid_utf8(true)
1361+
.required(true),
1362+
)
1363+
.try_get_matches_from(["test", "one"])
1364+
.unwrap()
1365+
.values_of_os("POTATO")
1366+
.expect("present")
1367+
.len();
1368+
assert_eq!(l, 1);
1369+
}
1370+
1371+
#[test]
1372+
fn indices_exact_size() {
1373+
let l = crate::App::new("test")
1374+
.arg(
1375+
crate::Arg::new("POTATO")
1376+
.takes_value(true)
1377+
.multiple_values(true)
1378+
.required(true),
1379+
)
1380+
.try_get_matches_from(["test", "one"])
1381+
.unwrap()
1382+
.indices_of("POTATO")
1383+
.expect("present")
1384+
.len();
1385+
assert_eq!(l, 1);
1386+
}
13231387
}

0 commit comments

Comments
 (0)