# Pre-RFC: PlatformFrom and PlatformInto

**URL:** <https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033>\
**Category:** libs\
**Created:** [March 27, 2020, 4:54am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033 "2020-03-27T04:54:12Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![joshlf](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/joshlf/32/3815_2.png) [@joshlf](https://internals.rust-lang.org/u/joshlf)\
**Post date:** [March 27, 2020, 4:54am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/1 "2020-03-27T04:54:12Z")

</div>

- Feature Name: platform\_from

- Start Date: (fill me in with today's date, YYYY-MM-DD)

- RFC PR: (leave this empty)

- Rust Issue: (leave this empty)

# Summary

Add the following traits to `core::convert` and `std::convert`, which are identical in structure to the existing `From` and `Into` traits:

```rust
pub trait PlatformFrom<T>: Sized {
    fn platform_from(_: T) -> Self;
}

pub trait PlatformInto<T>: Sized {
    fn platform_into(self) -> T;
}

impl<T, U> PlatformFrom<T> for U where U: From<T> { ... }
impl<T, U> PlatformInto<U> for T where U: PlatformFrom<T> { ... }

```

In addition, `U: PlatformFrom<T>` for all numeric primitives `T` and `U` such that the conversion is valid _on the current target platform_. For example, `usize: PlatformFrom<u32>` on 32- and 64-bit platforms.

# Motivation

The existing [From](https://doc.rust-lang.org/stable/core/convert/trait.From.html) and [Into](https://doc.rust-lang.org/stable/core/convert/trait.Into.html) traits are only defined for conversions which are valid _on all target platforms_. This means that they are unavailable to programmers developing platform-specific code even if a given conversion is valid _on the target platform_. For example, code written for a 32-bit platform cannot convert from a `u32` into a `usize` using these traits since the conversion is not valid on _all_ platforms.

This forces programmers in this situation to resort to a combination of the `as` keyword and comments explaining why the conversion is guaranteed to be lossless ([example](https://fuchsia-review.googlesource.com/c/mundane/+/375794/1/src/boringssl/raw.rs#586)). Since there is no compiler assistance, if the conversion becomes lossy in the future because the code is incorrectly ported to a different architecture, or used in a platform-agnostic context, etc, compilation will continue to succeed when it shouldn't, and the code may be wrong. In the context of `unsafe` code, this can lead to undefined behavior. In the context of safe code, it can still lead to unspecified behavior.

# Guide-level explanation

In the `core::convert` and `std::convert` modules, the following traits are added:

```rust
pub trait PlatformFrom<T>: Sized {
    fn platform_from(_: T) -> Self;
}

pub trait PlatformInto<T>: Sized {
    fn platform_into(self) -> T;
}

impl<T, U> PlatformFrom<T> for U where U: From<T> { ... }
impl<T, U> PlatformInto<U> for T where U: PlatformFrom<T> { ... }

```

In addition, `U: PlatformFrom<T>` for all numeric primitives `T` and `U` such that the conversion is valid _on the current target platform_. Note that, in practice, conversions between primitives whose size is not platform-dependent are already covered by existing `From` impls. Thus, the only added implementations are to or from `usize`, `isize`, `*const T`, and `*mut T`.

These traits are intended to be used _only_ in a platform-dependent context. In that context, their use is encouraged instead of the `as` keyword. When they are used, code which is either buggy or incorrectly ported to a different platform will stop compiling as soon as conversions which were supposed to be infallible become fallible.

# Reference-level explanation

Concretely, `U: PlatformFrom<T>` for the following types (other valid conversions like `u8 -> usize` are covered by existing `From` implementations, and thus receive a blanket `PlatformFrom` implementation):

### 32-bit platforms

| `T` | `U` |
| --- | --- |
| `u16` | `isize` |
| `u32` | `usize` |
| `i32` | `isize` |
| `usize` | `u32` |
| `usize` | `u64` |
| `usize` | `i64` |
| `usize` | `u128` |
| `usize` | `i128` |
| `isize` | `i32` |
| `isize` | `i64` |
| `isize` | `i128` |

### 64-bit platforms

| `T` | `U` |
| --- | --- |
| `u16` | `isize` |
| `u32` | `usize` |
| `u32` | `isize` |
| `i32` | `isize` |
| `u64` | `usize` |
| `i64` | `isize` |
| `usize` | `u64` |
| `usize` | `u128` |
| `usize` | `i128` |
| `isize` | `i64` |
| `isize` | `i128` |

In addition, for every `T: PlatformFrom<usize>` and `usize: PlatformFrom<T>` conversion listed in the preceding two tables, two more impls exist for `*const U` and `*mut U`, as const and mut raw pointers have the same memory layout as `usize`.

# Drawbacks

This adds more platform-dependent APIs to `core` and `std`, which is generally something we try to avoid.

# Rationale and alternatives

The two primary alternatives that the author is aware of are:

- Continue with the status quo - this is undesirable because it leads, in practice, to programmers using `as` for conversions, resulting in code whose correctness is not verified by the compiler
- Introduce platform-dependent impls of `From` and `Into` - this [has been discussed](https://internals.rust-lang.org/t/numeric-into-should-not-require-everyone-to-support-16-bit-and-128-bit-usize/3609), and its primary drawback is that it allows code to _accidentally_ become platform-dependent

The design presented in this RFC avoids the problems with both of these alternatives by a) providing the authors of platform-dependent code a mechanism for conversion which provides compiler verification that conversions are lossless and, b) designing the API in a way that will discourage platform-agnostic code from accidentally using it and thus becoming dependent on platform-specific behavior.

# Prior art

N/A

# Unresolved questions

- Where should these traits live? `{core,std}::convert` seems natural because of the existing `From` and `Into` traits, but those modules do not currently have any platform-dependent APIs.

- What should these traits (and their methods) be named?

- Are there any other impls that should be provided besides those listed in the Reference section?

---

<div class="post-metadata">

**Author:** ![eugene2k](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/eugene2k/32/3525_2.png) [@eugene2k](https://internals.rust-lang.org/u/eugene2k)\
**Post date:** [March 27, 2020, 6:35am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/2 "2020-03-27T06:35:16Z")

</div>

> [@joshlf](#):
>
> code written for a 32-bit platform cannot convert from a `u32` into a `usize`

Isn't `usize` 32 bits on a 32 bit platform?

---

<div class="post-metadata">

**Author:** ![joshlf](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/joshlf/32/3815_2.png) [@joshlf](https://internals.rust-lang.org/u/joshlf)\
**Post date:** [March 27, 2020, 6:40am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/3 "2020-03-27T06:40:52Z")

</div>

> [@eugene2k](#):
>
> Isn't `usize` 32 bits on a 32 bit platform?

It is. However, the only way you can do that conversion today is using `as`. The problem with `as` is that it also works for lossy conversions, so if your code depends on the conversion being lossless, it will compile in situations where the conversion is lossy even though you don't want it to. For some conversions (like `u16 -> usize`), you can use the `From` trait, but as described in the **Motivation** section, this trait is only implemented for conversions which are valid _on all platforms that Rust supports_. That doesn't help if you're trying to do something like `u32 -> usize` which is valid on the platform you happen to be developing for, but not on _all_ platforms.

---

<div class="post-metadata">

**Author:** ![eugene2k](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/eugene2k/32/3525_2.png) [@eugene2k](https://internals.rust-lang.org/u/eugene2k)\
**Post date:** [March 27, 2020, 7:14am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/4 "2020-03-27T07:14:39Z")

</div>

Oh, right! I misunderstood the sentence there.

---

<div class="post-metadata">

**Author:** ![petrochenkov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/petrochenkov/32/2784_2.png) [@petrochenkov](https://internals.rust-lang.org/u/petrochenkov)\
**Post date:** [March 27, 2020, 7:18am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/5 "2020-03-27T07:18:39Z")

</div>

We already have an accepted RFC resolving this problem - [https://github.com/rust-lang/rfcs/blob/master/text/1868-portability-lint.md](https://github.com/rust-lang/rfcs/blob/master/text/1868-portability-lint.md).

The `From` / `Into` should be implemented for all possible numeric types and the impls may be platform-specific, but largely non-portable impls should be linted.

Even without a general portability lint mechanism a lint for non-portable `From` / `Into` conversions can be implemented ([https://github.com/rust-lang/rust/pull/37423](https://github.com/rust-lang/rust/pull/37423)).

---

<div class="post-metadata">

**Author:** ![ratmice](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ratmice/32/4917_2.png) [@ratmice](https://internals.rust-lang.org/u/ratmice)\
**Post date:** [March 27, 2020, 7:24am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/6 "2020-03-27T07:24:10Z")

</div>

I know compiler feature-gating is usually only for unstable features, but would for this to retain feature gating after stablization. It would be nice if it still required a feature to enable, so you could have some files which enable the these Platform traits, and others which you don't have to worry about usage of these traits appearing in even though the target platform does support them.

---

<div class="post-metadata">

**Author:** ![joshlf](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/joshlf/32/3815_2.png) [@joshlf](https://internals.rust-lang.org/u/joshlf)\
**Post date:** [March 27, 2020, 7:44am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/7 "2020-03-27T07:44:55Z")

</div>

> [@petrochenkov](#):
>
> We already have an accepted RFC resolving this problem - [https://github.com/rust-lang/rfcs/blob/master/text/1868-portability-lint.md](https://github.com/rust-lang/rfcs/blob/master/text/1868-portability-lint.md).
> 
> The `From` / `Into` should be implemented for all possible numeric types and the impls may be platform-specific, but largely non-portable impls should be linted.

Ah, I didn't realize that the portability lint was intended to cover this case as well.

> [@petrochenkov](#):
>
> Even without a general portability lint mechanism a lint for non-portable `From` / `Into` conversions can be implemented ([https://github.com/rust-lang/rust/pull/37423](https://github.com/rust-lang/rust/pull/37423)).

Would it be possible to resurrect a PR like this one? I didn't quite follow the discussion about "scenarios" that led to it being closed, but it looks like scenarios were the precursor idea to the portability lint?

---

<div class="post-metadata">

**Author:** ![petrochenkov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/petrochenkov/32/2784_2.png) [@petrochenkov](https://internals.rust-lang.org/u/petrochenkov)\
**Post date:** [March 27, 2020, 8:06am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/8 "2020-03-27T08:06:28Z")

</div>

> [@joshlf](#):
>
> Would it be possible to resurrect a PR like this one?

Probably yes.  
Given that the portability lint RFC lies unimplement for years, a smaller focused solution could be acceptable.

---

<div class="post-metadata">

**Author:** ![joshlf](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/joshlf/32/3815_2.png) [@joshlf](https://internals.rust-lang.org/u/joshlf)\
**Post date:** [March 27, 2020, 8:08am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/9 "2020-03-27T08:08:31Z")

</div>

OK, cool. Do you think the same approach you used in that PR would still work? If so, I'd be happy to re-submit it (or we could just re-open that same PR I suppose).

---

<div class="post-metadata">

**Author:** ![petrochenkov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/petrochenkov/32/2784_2.png) [@petrochenkov](https://internals.rust-lang.org/u/petrochenkov)\
**Post date:** [March 27, 2020, 8:09am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/10 "2020-03-27T08:09:53Z")

</div>

That PR is 3.5 years old, it won't work as is and probably needs to be largely reimplemented.

---

<div class="post-metadata">

**Author:** ![joshlf](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/joshlf/32/3815_2.png) [@joshlf](https://internals.rust-lang.org/u/joshlf)\
**Post date:** [March 27, 2020, 8:10am UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/11 "2020-03-27T08:10:48Z")

</div>

OK, sounds good!

Edit: I've submitted an issue [here](https://github.com/rust-lang/rust/issues/70460) and submitted it to TWiR's CFP.

---

<div class="post-metadata">

**Author:** ![Speedy37](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/speedy37/32/2512_2.png) [@Speedy37](https://internals.rust-lang.org/u/Speedy37)\
**Post date:** [March 27, 2020, 1:24pm UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/12 "2020-03-27T13:24:23Z")

</div>

I wrote [https://crates.io/crates/usize\_cast](https://crates.io/crates/usize_cast) a few days ago (it focus only on from/into usize/isize).

I agree these conversions should be in core.

---

<div class="post-metadata">

**Author:** ![SimonSapin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simonsapin/32/3158_2.png) [@SimonSapin](https://internals.rust-lang.org/u/SimonSapin)\
**Post date:** [March 27, 2020, 1:27pm UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/13 "2020-03-27T13:27:20Z")

</div>

So far the precedent in the standard library is that non-portable APIs should require importing something from the `std::os` module, **in a sub-module named after the relevant platform**. For example `std::os::windows::process::CommandExt`. This shows to readers of the code:

1. That something non-portable is used
2. On what platforms that code is expected to compile

This RFC achieves 1. through having `Platform` in the traits name, but fails at 2: when reading `foo.platform_into()` I don’t know what platforms this is expected to be compatible with. I can figure it out based on the input and return type of the conversion, but those are often not obvious because of type inference.

I agree that there is a need here, but I’d prefer a solution where which platforms to target is an explicit choice. This could be some new modules like `std::os::ptr_size_ge_32bits` or `std::os::ptr_size_le_64bits` where `ge` and `le`mean "greater or equal" and "less than or equal", like in corresponding methods of the `PartialOrd` trait. (Names to be bikesheded.)

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [March 27, 2020, 1:58pm UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/14 "2020-03-27T13:58:58Z")

</div>

I have personally run into portability issues from a crate defining and using such a conversion in their public API without it being obvious

> <https://github.com/Geal/nom/issues/1029>
>
> I just discovered after upgrading a crate to nom 5.0.1 and switching to the function based API it would no longer...

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [June 25, 2020, 1:58pm UTC](https://internals.rust-lang.org/t/pre-rfc-platformfrom-and-platforminto/12033/15 "2020-06-25T13:58:59Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
