// in impl<T, A: Allocator> Vec<T, A>
fn try_into_single(mut self) -> Result<T, Vec<T, A>> {
if self.len() == 1 {
// SAFETY: We checked that the Vec is not empty, so this always returns Some(_)
Ok(unsafe { self.pop().unwrap_unchecked() })
} else {
Err(self)
}
}
Would other people find this useful in the standard library as well?
I'd need a match or unwrap_or_else instead of if let so I can use items in the 'else' branch. Luckily the TryFrom impl returns the original Vec in the Err variant.
Note that the OP example wants to keep the Vec in the else case, whereas the itertools option results in roughly (Option<(T, Option<T>)>, vec::Iter<T>). If all you need is some impl Iterator<Item=T> in the else case, then this is fine, but there's no way to recover the original vector other then collecting to a new one. (And unlike simple map/collect code, there isn't a specialization to reuse the existing vector.)
The project I was talking about is a language, written in Rust. Its AST contains lists everywhere. For example:
enum Node {
Literal(Literal), // "abc"
Group(Group), // (a b c)
Alternation(Alternation), // a | b | c
// ...omitted
}
struct Group {
span: Span,
children: Vec<Node>,
}
struct Alternation {
span: Span,
children: Vec<Node>
}
// ...etc
When transforming the AST to a different representation, there's often an optimization possible when a node contains only a single element. But using a OneOrMany enum for them is not feasible, as that would make the parser more complicated, and also interfere with other, unrelated code.
I don't see anything wrong with your original code. I think you misunderstand the purpose and potential drawbacks of unwrap(). Please read Andrew Gallant's great article on unwrap().
Not OP, but I regularly write Rust code in a context where any panic would be very bad. So any code that has to call a method that panics in a case which should be impossible (such as .unwrap() or .expect(..) on an option that should always be Some), has to come with a thorough justification of why the panicking case is impossible, which needs to be addressed each time the code is updated. Using an alternative method like this which allows an implementation that avoids potentially-panicking methods is a strict upgrade.
For cases where panicking on a bug in the program is acceptable, he makes a reasonable argument for .unwrap() being a potentially-idiomatic call, but not all cases have panicking as an acceptable option.
Which is reasonably self justifying. In rust I prefer the form if let Ok([item]) = <[_; 1]>::try_from(items) {, but this has more to do with moving the exhaustiveness check to compile time, especially since this pattern is repeated in many places in OP's codebase. In OP's place, prior to consulting this thread, I would probably have gone with a helper function.