Add `into_bounds()` to `RangeBounds` trait?

Right now there is no obvious way to get owned bounds out of an owned std::ops::RangeBounds<T> trait object unless T: Clone. Maybe I'm missing something? The cloned() method works for clonable stuff, but otherwise start_bound() and end_bound() only return references.

Could we add a required into_bounds() method to RangeBounds? It would destruct the trait object and return a tuple of owned start and end Bounds.

I have a (somewhat silly) use case for this. Should I file a feature request issue and/or put together a PR? What would be the process for this?

@josh maybe you have some thoughts? Is this the right place to discuss this? Am I missing something?

2 Likes

I don't think this is possible; RangeBounds is implemented for types that can provide a Bound<&T> but not a Bound<T>, such as impl<'a, T> RangeBounds<T> for (Bound<&'a T>, Bound<&'a T>) or impl<T> RangeBounds<T> for Range<&T>. Those impls couldn't supply into_bounds().

That's leaving aside that RangeBounds isn't a sealed trait, so it can have implementations outside the standard library, so it can't add any new required methods, only optional methods.

What's the use case for being able to do this without requiring T: Clone? Perhaps there's another way to solve that use case?

I've thought about this a bit. Have an ACP drafted. The primary use case is bounds that require an allocation like BigInts.

One way to accomplish this without : Clone is to introduce a new trait for it:

pub trait IntoBounds<T> {
    // Take `this: Self` if the function is on RangeBounds
    fn into_bounds(self) -> (Bound<T>, Bound<T>);
}

Then we could either have people just use that trait, or you could add a defaulted function to RangeBounds as well:

fn into_bounds() -> (Bound<T>, Bound<T>)
where
    Self: IntoBounds
{
    IntoBounds::into_bounds(self)
}

The other option is to just add

impl From<Range*<T>> for (Bound<T>, Bound<T>)

Then we could either have people just use from or into, or you could add a defaulted function to RangeBounds for convenience:

fn into_bounds() -> (Bound<T>, Bound<T>)
where
    Self: Into<(Bound<T>, Bound<T>)>
{
    self.into()
}
1 Like

I would take either of these.

I don't understand the cultural implications of IntoBounds vs From: I'm always confused by whether it's cool to implement From for things that aren't really type conversions. But it would work fine and avoid a new trait.

If we do either of these, I don't think there's any real need to add a convenience function to RangeBounds: just a note in the documentation would be sufficient, I think?

Let me know how I can help with the ACP.

Does https://doc.rust-lang.org/std/convert/trait.From.html#when-to-implement-from help at all? Any suggestions for ways that could be better explained to help you decide?

I think for the From/Into case, it would be extremely convenient to avoid needing to specify (Bound<T>, Bound<T>)