-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add cast
function to primitive integers
#42456
Conversation
r? @sfackler (rust_highfive has picked a reviewer for you, use r? to override) |
cc @rust-lang/libs Note I haven't allocated a tracking issue for this yet, wanted to discuss a bit to make sure we're all on board and then I'll open a tracking issue! |
/// not be performed losslessly. | ||
#[unstable(feature = "num_cast", issue = "0")] | ||
#[derive(Debug)] | ||
pub struct CastError(()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this separate error really needed? Why not an option based API? The ? operator is about to work with options as well, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intention is that you can define From<CastError> for MyError
and have ?
work in result-based functions, whereas in option base dfunctions you can just use cast(..).ok()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IDK, for me the operation feels similar to checked_add
and that returns an option as well. Or is the policy to return Result
everywhere for new APIs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's pretty difficult to create a blanket policy that works everywhere, but this is intended for use in APIs that are already dealing with calls to libc and such and are almost guaranteed to already be returning Result
.
src/libcore/num/cast.rs
Outdated
#[unstable(feature = "num_cast", issue = "0")] | ||
impl Cast<$unsigned> for $signed { | ||
fn cast(u: $unsigned) -> Result<$signed, CastError> { | ||
let max = <$signed>::max_value() as u128; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using u128 here I think we should rather implement a (non public) trait Signed
for each unsigned type that has an assoc type with the corresponding unsigned type, and then perform conversion via <$signed>::Unsigned
. At least as long as we can't prove that the u128 conversion is optimized away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is currently just copying the implementation for TryFrom
which has been in use for quite some time.
IMO |
My personal take on the a fallible conversion trait is that I think it'd almost replace the need for these methods altogether.
Are you sure you are the same @alexcrichton and library team as year ago?
rust-lang/rfcs#1218 contains some detailed discussion about this stuff (see the commit history as well), and methods that cast |
@nagisa I'm not in love with the name, I'd be down for other suggestions! |
A year is a long time, and people can certainly change opinions in that amount of time. |
@petrochenkov What is the purpose of that comment? What action would you like to see taken? |
@alexcrichton how about |
@petrochenkov Indeed, it's seeming like your RFC had it right. It's not the first time we've ended up long delaying one proposal on the basis of thinking that something more general would suffice, only to have it not really work out in the end. And I'm sure it won't be the last! To be honest, by this point I had totally forgotten about your RFC, and am glad you've re-raised it! We should definitely revisit the API you proposed as an alternative before landing this one. I'm particularly curious about the choice of having cc @rust-lang/libs |
src/libcore/num/cast.rs
Outdated
($storage:ty, $target:ty, $($source:ty),*) => {$( | ||
#[unstable(feature = "num_cast", issue = "0")] | ||
impl Cast<$source> for $target { | ||
fn cast(u: $source) -> Result<$target, CastError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These functions want an #[inline]
. I’ve observed in my Range specialisation PR that the casts won’t get inlined and inlining is able to get rid of the unnecessary code resulting in one or two instructions per cast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, forgot this originally, added now.
Since this is number-specific, I rather expected the checked/overflowing/wrapping/saturating methods, like @petrochenkov linked, for consistency with the other mathy methods. For example, |
☔ The latest upstream changes (presumably #42644) made this pull request unmergeable. Please resolve the merge conflicts. |
@scottmcm my personal hope is that we can make progress here as this feature has been stalled for years at this point now. Along those lines while I think such future additions may affect naming today I'd prefer to focus solely on one use case for now, FFI conversions. Those want the checked versions 99% of the time and to be usable also want them to be ergonomic. I'm just wary of continuing to bog down progress in the endless bikeshed of what methods, what names, and what signatures we want. My hope is that this strikes a right balance for ergonomics (usable with |
@nagisa I personally feel |
@alexcrichton I'm totally onboard with not having the saturating_ and other variants immediately. Let's see if I can better phrase as motivational statements:
|
☔ The latest upstream changes (presumably #42430) made this pull request unmergeable. Please resolve the merge conflicts. |
Merge conflicts! |
Rebased |
☔ The latest upstream changes (presumably #42780) made this pull request unmergeable. Please resolve the merge conflicts. |
This commit is a result of the libs team's discussion of rust-lang#33417 and how it affects integral types. The conclusion was that the motivation for converting integral types, working in a cross-platform code that uses platform-specific integer types, was different enough from the intent of `TryFrom` that it doesn't make sense to unify the paths. As a result this is a proposal for the alternative version of the API which purely works with integral types. An unstable `Cast` trait is added as the implementation detail of this API, and otherwise with this you should be able to call `i32::cast(0u8)` at will. The intention is then to call this in platform-specific contexts like: // Convert from C to Rust let a: c_int = ...; let b: u32 = u32::cast(a)?; // Convert from Rust to C let a: u32 = ...; let b: c_int = <c_int>::cast(a)?; Everything here is unstable for now, but the intention is that this will stabilize sooner than `TryFrom`.
@alexcrichton Not sure if this is legitimate. May just need to delete something? Either way, I believe this potentially need to be rebased -- not super clear about the current status.
|
@Mark-Simulacrum SUMMARY.MD should be autogenerated now, and create links on its own. One will probably have to rebase in order to get this autogeneration though. |
Are you still working on this @alexcrichton? Friendly ping to keep this on your radar. |
Which RFC is this based on? Which specific conversions are to be supported: signed -> unsigned, unsigned -> signed, potentially-lossy narrowing conversions? As was discussed in the RFC I'm aware of (rust-lang/rfcs#1218), each type of conversion should have a different name. In particular, potentially-lossy narrowing conversions should be called something like I also don't think there's anything special about FFI types. usize/isize vs fixed-width types have the same issues. |
I'm not sure about the procedure, but afaik smaller lib apis like this one can be added without an RFC. |
The closest in https://github.com/rust-lang/rfcs/blob/master/libs_changes.md#is-an-rfc-required is:
I think a new inherent method to primitive types is not a "hole patch", and @briansmith listed more than enough questions to show that details of this API are not obvious. I’ve seen and had RFCs be asked for much less than this. |
Yeah I agree. This at least needs more discussions as to why there's no methods for all the different kinds of possible casts you would want. This exists for overflow on all kinds of different operations, but here there's just the "checked" version available. |
Ok, I don't believe I have the time or energy to push this over the hump, so closing. |
@petrochenkov, are you interested in revisiting your RFC on this topic, now that the |
@aturon |
If nobody volunteers for this beforehand, I will pick up redoing the RFC in mid-August. |
@briansmith @petrochenkov Hi. Any update on the RFC? |
@kennytm |
@kennytm Sure, I will write a new RFC for this. Am I correct in understanding that it won't even be considered by the libs team until after January, though? Not sure how the "impl period" thing is working. |
@briansmith I think that depends on whether stabilizing Recently #44174 is submitted, so the FFI issue #33417 (comment) is becoming a real problem, which is the original reason why this PR exists. But it seems not definite that |
@briansmith The plan is to put our primary focus on implementation work during the impl period, so the question probably comes down to how much shepherding work would be required on the ensuing discussion. I'd suggest trying to get one open in the next ~week, which would leave some time for shepherding discussion prior to the impl period, and thus put us in a place where FCP shouldn't be too hard to reach. |
This commit is a result of the libs team's discussion of #33417 and how it
affects integral types. The conclusion was that the motivation for converting
integral types, working in a cross-platform code that uses platform-specific
integer types, was different enough from the intent of
TryFrom
that it doesn'tmake sense to unify the paths. As a result this is a proposal for the
alternative version of the API which purely works with integral types.
An unstable
Cast
trait is added as the implementation detail of this API, andotherwise with this you should be able to call
i32::cast(0u8)
at will. Theintention is then to call this in platform-specific contexts like:
Everything here is unstable for now, but the intention is that this will
stabilize sooner than
TryFrom
.