├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── charter.md ├── faq.md ├── langteam-sync └── README.md ├── periodic-summaries └── README.md ├── planning ├── project-planning.md └── roadmap │ └── README.md ├── resolved-concerns └── README.md ├── rfcs ├── 0000-ext-byte-transmutation.md ├── 0000-ext-container-casting.md ├── 0000-ext-generic-atomic.md ├── 0000-ext-include-data.md ├── 0000-ext-layout-traits.md ├── 0000-ext-promise-transmutable.md ├── 0000-safe-transmute.md └── announcement-and-charter.md └── terminology ├── misc.md └── spec-terminology.md /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all 9 | copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | SOFTWARE. 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project "safe transmute" 2 | 3 | A [working-group project][shepherds-blog] to extend the Rust language to 4 | support safe transmute 5 | 6 | - Shepherds: 7 | - [jswrenn (Jack)](https://github.com/jswrenn) 8 | - Rust lang team contacts: 9 | - [joshtriplett (Josh)](https://github.com/joshtriplett) 10 | - [Our chat room][zulip-room] 11 | - [Status updates](https://rust-lang.zulipchat.com/#narrow/stream/216762-project-safe-transmute/topic/Status) 12 | - [The (closed) RFC](https://github.com/rust-lang/project-safe-transmute/pull/5) 13 | - [The MCP](https://github.com/rust-lang/compiler-team/issues/411) 14 | 15 | [shepherds-blog]: http://smallcultfollowing.com/babysteps/blog/2019/09/11/aic-shepherds-3-0/ 16 | [zulip-room]: https://rust-lang.zulipchat.com/#narrow/stream/216762-project-safe-transmute 17 | 18 | # Contributing 19 | 20 | We do not have a formal concept of membership. Please feel free to join our 21 | [Zulip chat room][zulip-room] or to open a GitHub Issues and/or Pull Request. 22 | 23 | -------------------------------------------------------------------------------- /charter.md: -------------------------------------------------------------------------------- 1 | # Charter 2 | 3 | To extend the language to support safe transmute. 4 | -------------------------------------------------------------------------------- /faq.md: -------------------------------------------------------------------------------- 1 | ## FAQ questions 2 | -------------------------------------------------------------------------------- /langteam-sync/README.md: -------------------------------------------------------------------------------- 1 | This directory is for write-ups related to synchronous discussions between the 2 | safe transmute project WG and the Rust lang team. 3 | 4 | * "report" notes are write-ups to present to the lang team (may be less formal than the name would imply) 5 | * "meeting" notes are write-ups drafted during a team meeting 6 | -------------------------------------------------------------------------------- /periodic-summaries/README.md: -------------------------------------------------------------------------------- 1 | This directory is for summaries of project discussions (primarily in Zulip) 2 | over a certain period. 3 | 4 | The intent is to provide a quick way for anyone to catch up on recent project 5 | discussions and activity. The summaries may also be useful when working on 6 | other documents: 7 | 8 | * drafting lang team "sync" reports 9 | * Updating a "state of the project" document (currently does not exist) 10 | -------------------------------------------------------------------------------- /planning/project-planning.md: -------------------------------------------------------------------------------- 1 | ## Current action items 2 | 3 | 4 | ## Goals 5 | 6 | 7 | ## Meta 8 | 9 | * Have a sync meeting every week or maybe 2 weeks 10 | * all are welcome to come, hold on Zulip (?) or Zoom 11 | * discuss the conversations that occured over last period 12 | * try to summarize new points that were raised and add to an existing document that contains the "pros/cons" 13 | * when this document seems to be at a steady state, time for a decision 14 | * make our proposal and bring it to the lang team 15 | * announce result and give some time, then add to FAQ 16 | -------------------------------------------------------------------------------- /planning/roadmap/README.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | This directory contains details about particular items on the roadmap. 4 | -------------------------------------------------------------------------------- /resolved-concerns/README.md: -------------------------------------------------------------------------------- 1 | This directory stores "resolved concerns" -- basically, whenever there 2 | is a non-obvious tradeoff, we try to create a document that describes 3 | the tradeoff in full, and then documents the resolution we ultimately 4 | reached. Sometimes these documents include dissents, if not everyone 5 | agreed with the ultimate outcome. These documents can then later be 6 | referenced if needed to recall the reasoning involved. 7 | -------------------------------------------------------------------------------- /rfcs/0000-ext-byte-transmutation.md: -------------------------------------------------------------------------------- 1 | - Feature Name: byte_transmutations 2 | - Start Date: (fill me in with today's date, YYYY-MM-DD) 3 | - RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) 4 | - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) 5 | 6 | [safer transmutation]: 0000-safe-transmute.md 7 | [zerocopy]: https://crates.io/crates/zerocopy 8 | [bytemuck]: https://crates.io/crates/bytemuck 9 | 10 | # Summary 11 | [summary]: #summary 12 | 13 | This is a **library extension** to [safer transmutation] (i.e., it does not require additional compiler support) which introduces traits encoding common transmutation-conversions: *byte* transmutations: 14 | - `FromZeros`, implemented if `Self` is initializable from an equivalently-sized array of zeroed bytes. 15 | - `FromBytes`, implemented if `Self` is transmutable from an equivalently-sized array of initialized bytes. 16 | - `IntoBytes`, implemented if `Self` is transmutable into an equivalently-sized array of initialized bytes. 17 | 18 | # Motivation 19 | [motivation]: #motivation 20 | Transmutations of types to-and-from equivalently-sized buffers of bytes are perhaps the most common use-case of transmutation; e.g., `FromBytes` and `AsBytes` traits of [zerocopy] form the foundation of Fuchsia's Rust networking stack. These traits can be formulated soundly and completely via [safer transmutation], but the obvious formulations aren't viable; e.g.: 21 | ```rust 22 | // `Dst` is `FromBytes` if it can be safely transmuted *from* an 23 | // equivalently sized array of `u8`. 24 | unsafe impl FromBytes for Dst 25 | where 26 | Dst: TransmuteFrom<[u8; size_of::()]>, 27 | {} 28 | ``` 29 | At the time of writing, `size_of::()` *cannot* appear in this context. Our proposal provides implementation of these traits that do not rely on speculative advancements in const generics. 30 | 31 | Together, `IntoBytes` and `FromBytes` can form the basis of a [bytemuck]-like [`PlainOldData` trait](https://docs.rs/bytemuck/1.*/bytemuck/trait.Pod.html): 32 | ```rust 33 | /// Implemented by types that are "plain old data": 34 | pub unsafe trait PlainOldData 35 | where 36 | Neglect: TransmuteOptions 37 | {} 38 | 39 | unsafe impl PlainOldData for T 40 | where 41 | T: FromBytes + IntoBytes, 42 | Neglect: TransmuteOptions 43 | {} 44 | ``` 45 | 46 | # Reference-level explanation 47 | [reference-level-explanation]: #reference-level-explanation 48 | 49 | The implementations of these traits using [safer transmutation] follows: 50 | 51 | ## `FromZeros` 52 | Indicates that a type may be transmuted from an appropriately-sized array of zeroed bytes. This trait provide a safe alternative to [`mem::zeroed()`](https://doc.rust-lang.org/core/mem/fn.zeroed.html). 53 | 54 | ```rust 55 | pub unsafe trait FromZeros 56 | where 57 | Neglect: TransmuteOptions 58 | { 59 | /// Safely initialize `Self` from zeroed bytes. 60 | fn zeroed() -> Self 61 | where 62 | Neglect: SafeTransmuteOptions; 63 | 64 | /// Unsafely initialize `Self` from zeroed bytes. 65 | fn unsafe_zeroed() -> Self 66 | where 67 | Neglect: TransmuteOptions; 68 | } 69 | 70 | #[derive(Copy, Clone, PromiseTransmutableFrom, PromiseTransmutableInto)] 71 | #[repr(u8)] 72 | enum Zero { 73 | Zero = 0u8 74 | } 75 | 76 | unsafe impl FromZeros for Dst 77 | where 78 | Dst: TransmuteFrom<[Zero; usize::MAX], Neglect>, 79 | Neglect: TransmuteOptions 80 | { 81 | fn zeroed() -> Self 82 | where 83 | Neglect: SafeTransmuteOptions 84 | { 85 | [Zero; size_of::].transmute_into() 86 | } 87 | 88 | unsafe fn unsafe_zeroed() -> Self 89 | where 90 | Neglect: TransmuteOptions 91 | { 92 | [Zero; size_of::].unsafe_transmute_into() 93 | } 94 | } 95 | ``` 96 | 97 | ## `FromBytes` 98 | Indicates that a type may be transmuted from an appropriately-sized array of bytes. 99 | ```rust 100 | pub unsafe trait FromBytes 101 | where 102 | Neglect: TransmuteOptions 103 | {} 104 | 105 | unsafe impl FromBytes for Dst 106 | where 107 | Dst: TransmuteFrom<[u8; usize::MAX], Neglect>, 108 | Neglect: TransmuteOptions 109 | {} 110 | ``` 111 | 112 | ## `IntoBytes` 113 | Indicates that a type may be transmuted into an appropriately-sized array of bytes. 114 | ```rust 115 | #[marker] 116 | pub unsafe trait IntoBytes 117 | where 118 | Neglect: TransmuteOptions 119 | {} 120 | 121 | // covers `size_of::() >= 1` 122 | unsafe impl IntoBytes for Src 123 | where 124 | [Src: usize::MAX]: TransmuteInto<[u8; usize::MAX], Neglect>, 125 | Neglect: TransmuteOptions 126 | {} 127 | 128 | // covers `size_of::() == 0` 129 | unsafe impl IntoBytes for Src 130 | where 131 | Src: SizeEq<()>, 132 | Neglect: TransmuteOptions 133 | {} 134 | ``` 135 | -------------------------------------------------------------------------------- /rfcs/0000-ext-container-casting.md: -------------------------------------------------------------------------------- 1 | - Feature Name: castfrom 2 | - Start Date: (fill me in with today's date, YYYY-MM-DD) 3 | - RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) 4 | - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) 5 | 6 | [safer transmutation]: 0000-safe-transmute.md 7 | [zerocopy]: https://crates.io/crates/zerocopy 8 | [packet]: https://fuchsia-docs.firebaseapp.com/rust/packet 9 | 10 | # Summary 11 | [summary]: #summary 12 | 13 | This is a **library extension** to [safer transmutation] (i.e., it does not require additional compiler support) which introduces traits for transmute-like conversions between container-types like `Vec` and slices. 14 | 15 | # Motivation 16 | [motivation]: #motivation 17 | 18 | The [safer transmutation] API makes it possible to define safe mechanisms for transmuting the contents of slices and `Vec`s. These conversions are not, themselves, sound *transmutations*: neither the layout of slices nor `Vec`s are well-defined. However, they each provide `from_raw_parts` constructors that can be used to effectively transmute their contents. 19 | 20 | 21 | A slice cast is an operation that consumes `&'i [Src]` and produces `&'o [Dst]`. This conversion has both static and dynamic components. The length of a `&'i [Src]` is a dynamic quality of values of that type. If ths static sizes of `Src` and `Dst` differ, the length of `&'o [Dst]` will need to differ from that of `&'i [Src]` accordingly. The static component of this conversion is whether the layouts of `Src` and `Dst` even permit such a conversion---we can use `TransmuteFrom` to answer this: *Could a reference to a maximally-long array of `Src` be transmuted to an array of just one `Dst`?* 22 | 23 | Concretely: 24 | ```rust 25 | fn cast<'i, 'o, Src, Dst>(src: &'i [Src]) -> &'o [Dst] 26 | where 27 | &'o [Dst; 1]: TransmuteFrom<&'i [Src; usize::MAX]> 28 | { 29 | let len = size_of_val(src).checked_div(size_of::()).unwrap_or(0); 30 | unsafe { slice::from_raw_parts(src.as_ptr() as *const Dst, len) } 31 | } 32 | ``` 33 | 34 | The invariants imposed by [`Vec::from_raw_parts`](https://doc.rust-lang.org/alloc/vec/struct.Vec.html#method.from_raw_parts) are far stricter than those imposed by [`slice::from_raw_parts`](https://doc.rust-lang.org/core/slice/fn.from_raw_parts.html): we may only convert a `Vec` to `Vec` if: 35 | - `U` is transmutable from `T` 36 | - `U` has the same size as `T` 37 | - `U` has the same static alignment as `T` 38 | 39 | Concretely: 40 | ```rust 41 | fn cast(src: Vec) -> Vec 42 | where 43 | Dst: TransmuteFrom 44 | + AlignEq, 45 | + SizeEq, 46 | { 47 | let (ptr, len, cap) = src.into_raw_parts(); 48 | unsafe { Vec::from_raw_parts(ptr as *mut Dst, len, cap) } 49 | } 50 | ``` 51 | 52 | The above `cast` functions have a major ergonomic drawback: they require callers to reiterate their `where` bounds. The bounds that determine the castability of a type is more ergonomically encapsulated with a *single* trait bound whose name clearly communicates that casting is possible. 53 | 54 | # Guide-level explanation 55 | [guide-level-explanation]: #guide-level-explanation 56 | 57 | Mirroring the design of `TransmuteFrom`, this *could* take the form of a `CastFrom` trait: 58 | ```rust 59 | pub mod cast { 60 | 61 | /// Instantiate `Self` from a value of type `Src`. 62 | /// 63 | /// The reciprocal of [CastInto]. 64 | pub trait CastFrom 65 | where 66 | Neglect: options::CastOptions, 67 | { 68 | /// Instantiate `Self` by casting a value of type `Src`, safely. 69 | fn cast_from(src: Src) -> Self 70 | where 71 | Src: Sized, 72 | Self: Sized, 73 | Neglect: options::SafeCastOptions 74 | { 75 | unsafe { CastFrom::<_,Neglect>::unsafe_cast_from(src) } 76 | } 77 | 78 | /// Instantiate `Self` by casting a value of type `Src`, potentially safely. 79 | unsafe fn unsafe_cast_from(src: Src) -> Self 80 | where 81 | Src: Sized, 82 | Self: Sized, 83 | Neglect: options::CastOptions; 84 | } 85 | 86 | /// Options for casting. 87 | pub mod options { 88 | 89 | /// The super-trait of all *safe* casting options. 90 | #[marker] pub trait SafeCastOptions: CastOptions {} 91 | 92 | /// The super-trait of all casting options. 93 | #[marker] pub trait CastOptions {} 94 | 95 | impl SafeCastOptions for () {} 96 | impl CastOptions for () {} 97 | 98 | } 99 | } 100 | ``` 101 | ...for which implementations on `Vec` and slices will be provided. 102 | 103 | Using this foundation, it is trivial to define the abstractions of the [zerocopy] and [packet] crates; e.g.: 104 | ```rust 105 | impl<'a> &'a [u8] 106 | { 107 | /// Read `&T` off the front of `self`, and shrink the underlying slice. 108 | /// Analogous to: 109 | /// - https://fuchsia-docs.firebaseapp.com/rust/packet/trait.BufferView.html#method.peek_obj_front 110 | /// - https://fuchsia-docs.firebaseapp.com/rust/packet/trait.BufferView.html#method.take_obj_front 111 | fn take_front<'t, T>(&'a mut self) -> Option<&'a T> 112 | where 113 | Self: CastInto<&'a [T]>, 114 | { 115 | let idx = size_of::(); 116 | let (parsable, remainder) = self.split_at(idx); 117 | *self = remainder; 118 | parsable.cast_into().first() 119 | } 120 | 121 | /// Read `&T` off the back of `self`, and shrink the underlying slice. 122 | /// Analogous to: 123 | /// - https://fuchsia-docs.firebaseapp.com/rust/packet/trait.BufferView.html#method.peek_obj_back 124 | /// - https://fuchsia-docs.firebaseapp.com/rust/packet/trait.BufferView.html#method.take_obj_back 125 | fn take_back<'t, T>(&'a mut self) -> Option<&'a T> 126 | where 127 | Self: CastInto<&'a [T]>, 128 | { 129 | let idx = self.len().saturating_sub(size_of::()); 130 | let (remainder, parsable) = self.split_at(idx); 131 | *self = remainder; 132 | parsable.cast_into().first() 133 | } 134 | } 135 | ``` 136 | 137 | To parse a `UdpPacket` given a byte slice, we split the slice into a slice containing first 8 bytes, and the remainder. We then cast the first slice into a reference to a `UdpHeader`. A `UdpPacket`, then, consists of the reference to the `UdpHeader`, and the remainder slice. Concretely: 138 | ```rust 139 | pub struct UdpPacket<'a> { 140 | hdr: &'a UdpHeader, 141 | body: &'a [u8], 142 | } 143 | 144 | #[derive(PromiseTransmutableFrom, PromiseTransmutableInto)] 145 | #[repr(C)] 146 | struct UdpHeader { 147 | src_port: [u8; 2], 148 | dst_port: [u8; 2], 149 | length: [u8; 2], 150 | checksum: [u8; 2], 151 | } 152 | 153 | impl<'a> UdpPacket<'a> { 154 | pub fn parse(mut bytes: &'a [u8]) -> Option { 155 | Some(UdpPacket { hdr: {bytes.take_front()?}, body: bytes }) 156 | } 157 | } 158 | ``` 159 | (While this example is simple, the technique can be [expanded](https://fuchsia-docs.firebaseapp.com/rust/packet_formats/) to arbitrarily complex structures.) 160 | 161 | 162 | # Reference-level explanation 163 | [reference-level-explanation]: #reference-level-explanation 164 | 165 | This `CastFrom` trait might then be implemented like so for `Vec`: 166 | ```rust 167 | /// A contiguous growable array type with heap-allocated contents, `Vec`. 168 | pub mod vec { 169 | use core::convert::{ 170 | transmute::{ 171 | TransmuteFrom, 172 | options::{SafeTransmuteOptions, TransmuteOptions, NeglectAlignment}, 173 | }, 174 | cast::{ 175 | CastFrom, 176 | options::{ 177 | SafeCastOptions, 178 | CastOptions, 179 | }, 180 | }, 181 | }; 182 | 183 | /// Safe options for casting `Vec` to `Vec`. 184 | pub trait SafeVecCastOptions 185 | : SafeCastOptions 186 | + SafeTransmuteOptions 187 | + VecCastOptions 188 | {} 189 | 190 | /// Options for casting `Vec` to `Vec`. 191 | pub trait VecCastOptions 192 | : TransmuteOptions 193 | + CastOptions 194 | {} 195 | 196 | impl SafeCastOptions for Neglect {} 197 | impl SafeVecCastOptions for Neglect {} 198 | 199 | impl CastOptions for Neglect {} 200 | impl VecCastOptions for Neglect {} 201 | 202 | 203 | use core::mem::{MaybeUninit, SizeEq, AlignEq}; 204 | 205 | impl CastFrom, Neglect> for Vec 206 | where 207 | Neglect: VecCastOptions, 208 | Dst: TransmuteFrom 209 | + AlignEq 210 | + SizeEq, 211 | { 212 | #[doc(hidden)] 213 | #[inline(always)] 214 | unsafe fn unsafe_cast_from(src: Vec) -> Vec 215 | { 216 | let (ptr, len, cap) = src.into_raw_parts(); 217 | Vec::from_raw_parts(ptr as *mut Dst, len, cap) 218 | } 219 | } 220 | } 221 | ``` 222 | 223 | ...and like so for slices: 224 | ```rust 225 | pub mod slice { 226 | use core::convert::{ 227 | transmute::{ 228 | TransmuteFrom, 229 | options::{SafeTransmuteOptions, TransmuteOptions}, 230 | }, 231 | cast::{ 232 | CastFrom, 233 | options::{ 234 | SafeCastOptions, 235 | CastOptions, 236 | }, 237 | }, 238 | }; 239 | 240 | use core::{ 241 | mem::{size_of, size_of_val}, 242 | slice 243 | }; 244 | 245 | /// *Safe* options for casting **slices**. 246 | pub trait SafeSliceCastOptions 247 | : SafeCastOptions 248 | + SafeTransmuteOptions 249 | + SliceCastOptions 250 | {} 251 | 252 | /// Options for casting **slices**. 253 | pub trait SliceCastOptions 254 | : CastOptions 255 | + TransmuteOptions 256 | {} 257 | 258 | impl SafeCastOptions for Neglect {} 259 | impl SafeSliceCastOptions for Neglect {} 260 | 261 | impl CastOptions for Neglect {} 262 | impl SliceCastOptions for Neglect {} 263 | 264 | 265 | impl<'i, 'o, Src, Dst, Neglect> CastFrom<&'i [Src], Neglect> for &'o [Dst] 266 | where 267 | Neglect: SliceCastOptions, 268 | &'o [Dst; 1]: TransmuteFrom<&'i [Src; usize::MAX], Neglect> 269 | { 270 | unsafe fn unsafe_cast_from(src: &'i [Src]) -> &'o [Dst] 271 | { 272 | let len = size_of_val(src).checked_div(size_of::()).unwrap_or(0); 273 | unsafe { slice::from_raw_parts(src.as_ptr() as *const Dst, len) } 274 | } 275 | } 276 | 277 | impl<'i, 'o, Src, Dst, Neglect> CastFrom<&'i mut [Src], Neglect> for &'o mut [Dst] 278 | where 279 | Neglect: SliceCastOptions, 280 | &'o mut [Dst; 1]: TransmuteFrom<&'i mut [Src; usize::MAX], Neglect> 281 | { 282 | unsafe fn unsafe_cast_from(src: &'i mut [Src]) -> &'o mut [Dst] 283 | { 284 | let len = size_of_val(src).checked_div(size_of::()).unwrap_or(0); 285 | unsafe { slice::from_raw_parts_mut(src.as_ptr() as *mut Dst, len) } 286 | } 287 | } 288 | 289 | impl<'i, 'o, Src, Dst, Neglect> CastFrom<&'i mut [Src], Neglect> for &'o [Dst] 290 | where 291 | { 292 | unsafe fn unsafe_cast_from(src: &'i mut [Src]) -> &'o [Dst] 293 | { 294 | let len = size_of_val(src).checked_div(size_of::()).unwrap_or(0); 295 | unsafe { slice::from_raw_parts(src.as_ptr() as *const Dst, len) } 296 | } 297 | } 298 | } 299 | ``` 300 | -------------------------------------------------------------------------------- /rfcs/0000-ext-generic-atomic.md: -------------------------------------------------------------------------------- 1 | - Feature Name: generic_atomic 2 | - Start Date: (fill me in with today's date, YYYY-MM-DD) 3 | - RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) 4 | - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) 5 | 6 | [safer transmutation]: 0000-safe-transmute.md 7 | 8 | # Summary 9 | [summary]: #summary 10 | 11 | This is a **library extension** to [safer transmutation] (i.e., it does not require additional compiler support) which introduces `Atomic`. 12 | 13 | # Motivation 14 | [motivation]: #motivation 15 | 16 | Rust defines a dozen `Atomic*` types (`AtomicBool`, `AtomicI8`, `AtomicI16`, `AtomicI32`, `AtomicI64`, `AtomicIsize`, `AtomicPtr`, `AtomicU8`, `AtomicU16`, `AtomicU32`, `AtomicU64`, and `AtomicUsize`). 17 | 18 | This set is large—a distinct `Atomic*` type is required for each primitive type—but incomplete. If one wants atomic operations on their own type, they must define a wrapper around an existing `Atomic*` type of appropriate size and validity, then transmute at API boundaries; e.g.: 19 | 20 | ```rust 21 | #[repr(u8)] 22 | enum Trilean { 23 | False, 24 | True, 25 | Unknown, 26 | } 27 | 28 | #[repr(transparent)] 29 | pub AtomicTrilean(AtomicU8); 30 | 31 | impl AtomicTrilean { 32 | 33 | pub const fn new(v: Trilean) -> Self { 34 | AtomicTrilean( 35 | AtomicU8::new( 36 | unsafe { mem::transmute(v) } 37 | )) 38 | } 39 | 40 | ... 41 | } 42 | ``` 43 | 44 | The [safer transmutation] mechanisms permit a truly-generic `Atomic` type. 45 | 46 | # Reference-level explanation 47 | [reference-level-explanation]: #reference-level-explanation 48 | 49 | Using the [safe transmutation] mechanisms, `Atomic` might be defined like so: 50 | 51 | ```rust 52 | type LargestPlatformAtomic = u64; // platform-dependent 53 | 54 | pub struct Atomic 55 | where 56 | T: SizeLtEq 57 | { 58 | v: UnsafeCell 59 | } 60 | 61 | impl Atomic 62 | { 63 | #[inline] 64 | pub fn load(&self, order: Ordering) -> T { 65 | unsafe { atomic_load(self.v.get(), order) } 66 | } 67 | 68 | #[inline] 69 | pub fn store(&self, val: T, order: Ordering) -> T { 70 | unsafe { atomic_store(self.v.get(), val, order) } 71 | } 72 | } 73 | ``` -------------------------------------------------------------------------------- /rfcs/0000-ext-include-data.md: -------------------------------------------------------------------------------- 1 | - Feature Name: include_data 2 | - Start Date: (fill me in with today's date, YYYY-MM-DD) 3 | - RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) 4 | - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) 5 | 6 | [safer transmutation]: 0000-safe-transmute.md 7 | 8 | # Summary 9 | [summary]: #summary 10 | 11 | This is a **library extension** to [safer transmutation] (i.e., it does not require additional compiler support) which introduces `include_data!`, a safe, generic alternative to `include_bytes!`. 12 | 13 | # Motivation 14 | [motivation]: #motivation 15 | 16 | Rust's [`include_bytes!` macro](https://doc.rust-lang.org/core/macro.include_bytes.html) lets you statically include the contents of a file into your executable's binary. The builtin is a quick-and-dirty solution for packaging data with your executable, and perhaps even helping the compiler optimize your code. **Unfortunately, it's difficult to use correctly.** Consider: 17 | ```rust 18 | pub fn recognize(input: &Matrix) -> usize 19 | { 20 | static RAW_WEIGHT : &'static [u8; 62_720] = include_bytes!("/weight.bin"); 21 | 22 | static RAW_BIAS : &'static [u8; 80] = include_bytes!("/bias.bin"); 23 | 24 | let WEIGHT: &Matrix = unsafe{ mem::transmute(RAW_WEIGHT) }; 25 | 26 | let BIAS: &Matrix = unsafe{ mem::transmute(RAW_BIAS) }; 27 | 28 | network::recognize(input, WEIGHT, BIAS) 29 | } 30 | ``` 31 | This is memory-unsafe, because `RAW_WEIGHT` and `RAW_BIAS` might not meet the alignment requirements of `Matrix`. This fix is subtle: 32 | ```rust 33 | pub fn recognize(input: &Matrix) -> usize 34 | { 35 | static RAW_WEIGHT : &'static [u8; 62_720] = include_bytes!("/weight.bin"); 36 | 37 | static RAW_BIAS : &'static [u8; 80] = include_bytes!("/bias.bin"); 38 | 39 | let WEIGHT: &Matrix = unsafe{ &mem::transmute(*RAW_WEIGHT) }; 40 | 41 | let BIAS: &Matrix = unsafe{ &mem::transmute(*RAW_BIAS) }; 42 | 43 | network::recognize(input, WEIGHT, BIAS) 44 | } 45 | ``` 46 | Even still, there is potential for undefined behavior: `mem::transmute` does almost nothing to ensure that the included bytes are a *valid* instance of `Matrix`. This RFC proposes a **safe** `include_transmute!` macro that lacks these disadvantages; e.g.: 47 | ```rust 48 | pub fn recognize(input: &Matrix) -> usize 49 | { 50 | static WEIGHT: &Matrix = include_transmute!("/weight.bin"); 51 | 52 | static BIAS: &Matrix = include_transmute!("/weight.bin"); 53 | 54 | network::recognize(input, &WEIGHT, &BIAS) 55 | } 56 | ``` 57 | 58 | # Reference-level explanation 59 | [reference-level-explanation]: #reference-level-explanation 60 | 61 | Using the [safe transmutation] mechanisms, `include_transmute!` might be defined like so: 62 | 63 | ```rust 64 | macro_rules! include_transmute { 65 | ($file:expr) => {{ 66 | use core::convert::transmute::*; 67 | &safe_transmute<_, _, ()>(*include_bytes!($file)) 68 | }}; 69 | } 70 | ``` -------------------------------------------------------------------------------- /rfcs/0000-ext-layout-traits.md: -------------------------------------------------------------------------------- 1 | - Feature Name: layout_traits 2 | - Start Date: (fill me in with today's date, YYYY-MM-DD) 3 | - RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) 4 | - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) 5 | 6 | [safer transmutation]: 0000-safe-transmute.md 7 | 8 | # Summary 9 | [summary]: #summary 10 | 11 | This is a **library extension** to [safer transmutation] (i.e., it does not require additional compiler support) which introduces traits that are implemented depending on the sizes and alignments of two given types: 12 | - `mem::AlignLtEq`, implemented for `Lhs` if `align_of::() <= align_of::` 13 | - `mem::AlignEq`, implemented for `Lhs` if `align_of::() == align_of::` 14 | - `mem::SizeLtEq`, implemented for `Lhs` if `size_of::() <= size_of::` 15 | - `mem::SizeEq`, implemented for `Lhs` if `size_of::() == size_of::` 16 | 17 | # Motivation 18 | [motivation]: #motivation 19 | 20 | Some abstractions that depend on a type's layout are more easier thought of in terms of size or alignment constraints than transmutability. For instance: 21 | 22 | ## Pointer Bit Packing 23 | A common bit-packing technique involves abusing the relationship between allocations and alignment. If a type is aligned to 2n, then the *n* least significant bits of pointers to that type will equal `0`. These known-zero bits can be packed with data. Since alignment cannot be currently reasoned about at the type-level, it's currently impossible to bound instantiations of a generic parameter based on minimum alignment. 24 | 25 | Using [safer transmutation], we can require that a reference to a generic type `T` has alignment of at least a given value (e.g., `8`) by first defining a ZST with that alignment: 26 | ```rust 27 | #[derive(PromiseTransmutableFrom)] 28 | #[repr(align(8))] 29 | struct Aligned8; 30 | ``` 31 | and then adding this `where` bound to our abstraction: 32 | ```rust 33 | where 34 | &T: TransmuteInto<&Aligned8> 35 | ``` 36 | 37 | The intuition behind this trait bound requires a thorough understanding of transmutability. With this RFC, this bound would be more clearly expressed as: 38 | ```rust 39 | #[repr(align(8))] 40 | struct Aligned8; 41 | ``` 42 | using this where bound: 43 | ```rust 44 | where 45 | Aligned8: mem::AlignLtEq, // Essentially T: AlignGtEq, but there is no AlignGtEq trait. 46 | ``` 47 | 48 | ## `Vec` Casting 49 | The invariants imposed by [`Vec::from_raw_parts`](https://doc.rust-lang.org/alloc/vec/struct.Vec.html#method.from_raw_parts) stipulate that we may only convert a `Vec` to `Vec` if: 50 | - `U` is transmutable from `T` 51 | - `U` has the same minimum alignment as `T` 52 | - `U` has the same size as `T` 53 | 54 | With this RFC, these requirements may be written directly: 55 | ```rust 56 | fn cast(src: Vec) -> Vec 57 | where 58 | Dst: TransmuteFrom 59 | + AlignEq, 60 | + SizeEq, 61 | { 62 | let (ptr, len, cap) = src.into_raw_parts(); 63 | unsafe { Vec::from_raw_parts(ptr as *mut Dst, len, cap) } 64 | } 65 | ``` 66 | 67 | # Reference-level explanation 68 | [reference-level-explanation]: #reference-level-explanation 69 | 70 | Given `TransmuteFrom` and `TransmuteInto`, we can construct bounds that check certain properties of a type by checking if its convertible to another, contrived type. These gadgets are useful, but subtle to formulate. 71 | 72 | ## Querying Alignment 73 | The type `[T; 0]` shares the alignment requirements of `T`, but no other layout properties. A type `&[T; 0]` will only be transmutable to `&[U; 0]`, if the minimum alignment of `T` is greater than that of `U`. We exploit this to define a trait that is implemented for `Self` if its alignment is less-than-or-equal to that of `Rhs`: 74 | ```rust 75 | /// Implemented if `align_of::() <= align_of::()` 76 | pub trait AlignLtEq 77 | where 78 | Neglect: TransmuteOptions, 79 | {} 80 | 81 | impl AlignLtEq for Lhs 82 | where 83 | Neglect: TransmuteOptions, 84 | for<'a> &'a [Lhs; 0]: TransmuteFrom<&'a [Rhs; 0], Neglect> 85 | {} 86 | ``` 87 | Furthermore, if the alignment of `Self` is less-than-or-equal to `Rhs`, and the alignment of `Rhs` is less-than-or-equal to `Self`, then the alignments of `Self` and `Rhs` must be equal: 88 | ```rust 89 | /// Implemented if `align_of::() == align_of::()` 90 | pub trait AlignEq 91 | where 92 | Neglect: TransmuteOptions, 93 | {} 94 | 95 | impl AlignEq for Lhs 96 | where 97 | Neglect: TransmuteOptions, 98 | Lhs: AlignLtEq, 99 | Rhs: AlignLtEq, 100 | {} 101 | ``` 102 | 103 | ## Querying Size 104 | Querying *just* the size of a type is trickier: how might we query the size without implicitly querying the alignment and validity of the bytes that contribute to that size? 105 | 106 | We do so by constructing a contrived container type that neutralizes the alignment and validity aspects of its contents: 107 | ```rust 108 | #[derive(PromiseTransmutableFrom, PromiseTransmutableInto)] */ 109 | #[repr(C)] 110 | struct Gadget(pub [Align; 0], pub MaybeUninit); 111 | ``` 112 | This type will have the size of `Size`, and alignment equal to the maximum of `Align` and `Size`. `MaybeUninit` neutralizes the bit-validity qualities of `Size`. 113 | 114 | We use this `Gadget` to define a trait that is implemented if the size of `Self` is less-than-or-equal to the size of `Rhs`: 115 | ```rust 116 | /// Implemented if `size_of::() <= size_of::()` 117 | pub trait SizeLtEq 118 | where 119 | Neglect: TransmuteOptions, 120 | {} 121 | 122 | impl SizeLtEq for Lhs 123 | where 124 | Neglect: TransmuteOptions, 125 | for<'a> &'a Gadget: TransmuteFrom<&'a Gadget, Neglect>, 126 | {} 127 | ``` 128 | This works, because `Gadget` and `Gadget` will have equal alignment, and equal bit-validity (they consist solely of padding bytes). Thus, all that varies between them is their size, and reference transmutations must either preserve or reduce the size of the transmuted type. 129 | 130 | As before, if the size of `Self` is less-than-or-equal to `Rhs`, and the size of `Rhs` is less-than-or-equal to `Self`, then the sizes of `Self` and `Rhs` must be equal: 131 | ```rust 132 | /// Implemented if `size_of::() == size_of::()` 133 | pub trait SizeEq 134 | where 135 | Neglect: TransmuteOptions, 136 | {} 137 | 138 | impl SizeEq for Lhs 139 | where 140 | Neglect: TransmuteOptions, 141 | Lhs: SizeLtEq, 142 | Rhs: SizeLtEq, 143 | {} 144 | ``` 145 | 146 | # Prior art 147 | [prior-art]: #prior-art 148 | 149 | The [FromBits](https://github.com/joshlf/rfcs/blob/joshlf/from-bits/text/0000-from-bits.md#sizeleq-and-alignleq) pre-RFC, recommends adding two similar traits: `AlignLeq` and `SizeLeq`. This pre-RFC envisions these traits as requiring additional compiler support; our proposal formulates equivalent traits just using [safer transmutation]. 150 | -------------------------------------------------------------------------------- /rfcs/0000-ext-promise-transmutable.md: -------------------------------------------------------------------------------- 1 | - Feature Name: promise_transmutable 2 | - Start Date: (fill me in with today's date, YYYY-MM-DD) 3 | - RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) 4 | - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) 5 | 6 | [safer transmutation]: 0000-safe-transmute.md 7 | [zerocopy]: https://crates.io/crates/zerocopy 8 | [bytemuck]: https://crates.io/crates/bytemuck 9 | 10 | # Summary 11 | [summary]: #summary 12 | 13 | This is a compiler-suported extension to [safer transmutation], adding `#[derive(PromiseTransmutable)]`, which expands to `#[derive(PromiseTransmutableFrom, PromiseTransmutableInto)]`. 14 | 15 | # Motivation 16 | [motivation]: #motivation 17 | 18 | We anticipate that *most* users will merely want to promise that their types are as-stable-as-possible. To do so, [safer transmutation] provides this shorthand: 19 | ```rust 20 | #[derive(PromiseTransmutableFrom, PromiseTransmutableInto)] 21 | #[repr(C)] 22 | pub struct Foo(pub Bar, pub Baz); 23 | ``` 24 | As a shorthand, this is still rather long. For such users, the separability of `PromiseTransmutableFrom` and `PromiseTransmutableInto` is totally irrelevant. 25 | 26 | # Guide-level explanation 27 | [guide-level-explanation]: #guide-level-explanation 28 | 29 | We propose a `derive(PromiseTransmutable)` shorthand, such that this: 30 | ```rust 31 | #[derive(PromiseTransmutable)] 32 | #[repr(C)] 33 | pub struct Foo(pub Bar, pub Baz); 34 | ``` 35 | ...is equivalent to this: 36 | ```rust 37 | #[derive(PromiseTransmutableFrom, PromiseTransmutableInto)] 38 | #[repr(C)] 39 | pub struct Foo(pub Bar, pub Baz); 40 | ``` 41 | 42 | # Reference-level explanation 43 | [reference-level-explanation]: #reference-level-explanation 44 | 45 | We caution *against* adding a corresponding trait or trait alias; e.g.: 46 | ```rust 47 | trait PromiseTransmutable = PromiseTransmutableFrom + PromiseTransmutableInto; 48 | ``` 49 | The vast majority of users will *only* confront the stability declaration traits in the context of deriving them; the *only* scenario in which end-users will refer to these traits in a type-context is the rare use-case of *manually* implementing them. For such users, the separability of `PromiseTransmutableFrom` and `PromiseTransmutableInto` *is* relevant. The availability of a `PromiseTransmutable` trait or trait alias in this scenario would be a distraction, since referring to it in a type-context is almost certainly a misstep. 50 | 51 | # Drawbacks 52 | [drawbacks]: #drawbacks 53 | 54 | We acknowledge that it is unusual for a `derive` macro to not implement an item of the same name, but this weirdness is outweighed by the weirdness of the alternative: providing a trait for which there is almost no good use. 55 | -------------------------------------------------------------------------------- /rfcs/0000-safe-transmute.md: -------------------------------------------------------------------------------- 1 | # Safer Transmute RFC 2 | 3 | - Feature Name: `safer_transmute` 4 | - Start Date: (fill me in with today's date, YYYY-MM-DD) 5 | - RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) 6 | - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) 7 | 8 | 9 | # Summary 10 | [summary]: #summary 11 | 12 | We propose traits, namely `TransmuteInto` and `TransmuteFrom`, that are implemented *automatically* for combinations of types that may be safely transmuted. In other words, this RFC makes safe transmutation *as easy as 1..., 2..., `repr(C)`!* 13 | ```rust 14 | use core::transmute::{ 15 | TransmuteInto, 16 | stability::{PromiseTransmutableInto, PromiseTransmutableFrom}, 17 | }; 18 | 19 | #[derive(PromiseTransmutableInto, PromiseTransmutableFrom)] // declare `Foo` to be *stably* transmutable 20 | #[repr(C)] 21 | pub struct Foo(pub u8, pub u16); 22 | // ^ there's a padding byte here, between these fields 23 | 24 | // Transmute fearlessly! 25 | let _ : Foo = 64u32.transmute_into(); // Alchemy Achieved! 26 | // ^^^^^^^^^^^^^^ provided by the `TransmuteInto` trait 27 | 28 | let _ : u32 = Foo(16, 12).transmute_into(); // Compile Error! 29 | 30 | // error[E0277]: the trait bound `u32: TransmuteFrom` is not satisfied 31 | // --> src/demo.rs:15:27 32 | // | 33 | // 15 | let _ : u32 = Foo(16, 12).transmute_into(); // Compile Error! 34 | // | ^^^^^^^^^^^^^^ the trait `TransmuteFrom` is not implemented for `u32` 35 | // | 36 | // = note: required because of the requirements on the impl of `TransmuteInto` for `foo::Foo` 37 | // = note: byte 8 of the source type may be uninitialized; byte 8 of the destination type cannot be uninitialized. 38 | ``` 39 | 40 | 41 | # Motivation 42 | [motivation]: #motivation 43 | 44 | Byte-reinterpretation conversions (such as those performed by `mem::transmute`, `mem::transmute_copy`, pointer casts, and `union`s) are invaluable in high performance contexts, are `unsafe`, and easy to get wrong. This RFC provides mechanisms that make many currently-unsafe transmutations entirely safe. For transmutations that are not entirely safe, this RFC's mechanisms make mistakes harder to make. 45 | 46 | This RFC's comprehensive approach provides additional benefits beyond the mere act of transmutation; namely: 47 | - [authoritatively codifies language layout guarantees](#codifying-language-layout-guarantees) 48 | - [allows crate authors to codify their types' layout stability guarantees](#expressing-library-layout-guarantees) 49 | - [allows crate authors to codify their abstractions' layout requirements](#expressing-layout-requirements) 50 | 51 | Given the expressive foundation provided by this RFC, we also envision a range of future possibilities that will *not* require additional compiler support, including: 52 | - [safe slice and `Vec` casting](0000-ext-container-casting.md) 53 | - [a unified, generic `Atomic` type](0000-ext-generic-atomic.md) 54 | - [a safe, generic alternative to `include_bytes!`](0000-ext-include-data.md) 55 | - [traits for asserting the size and alignment relationships of types](0000-ext-layout-traits.md) 56 | - [zerocopy-style traits for safe initialization](0000-ext-byte-transmutation.md) 57 | - [bytemuck-style mechanisms for fallible reference casting][ext-ref-casting] 58 | 59 | 60 | ## Codifying Language Layout Guarantees 61 | Documentation of Rust's layout guarantees for a type are often spread across countless issues, pull requests, RFCs and various official resources. It can be very difficult to get a straight answer. When transmutation is involved, users must reason about the *combined* layout properties of the source and destination types. 62 | 63 | This RFC proposes mechanisms that programmers will use to confidently answer such questions—by checking whether the `TransmuteFrom` and `TransmuteInto` traits are implemented, or (equivalently) by checking whether the `can_transmute` predicate (a `const fn`) is satisfied. 64 | 65 | ## Expressing Library Layout Guarantees 66 | There is no canonical way for crate authors to declare the SemVer layout guarantees of their types. Crate authors currently must state their layout guarantees using prose in their documentation. In contrast to structural stability (e.g., the declared visibility of fields), layout stability is expressed extra-linguistically. 67 | 68 | This isn't satisfactory: guarantees expressed in prose outside of the Rust programming language are guarantees that cannot be reasoned about *inside* the language. Whereas `rustc` can dutifully deny programmers access to private fields, it is unable to prevent programmers from making unfounded expectations of types' in-memory layouts. 69 | 70 | This RFC proposes simple-but-powerful [mechanisms][stability] for declaring layout stability guarantees. 71 | 72 | ## Expressing Layout Requirements 73 | Similarly, there is no canonical way for crate authors to declare the layout requirements of generic abstractions over types that have certain layout properties. 74 | 75 | For instance, a common bit-packing technique involves using the relationship between allocations and alignment. If a type is aligned to 2n, then the *n* least significant bits of pointers to that type will equal `0`. These known-zero bits can be packed with data. Since alignment cannot be currently reasoned about at the type-level, it's currently impossible to bound instantiations of a generic parameter based on minimum alignment. 76 | 77 | The mechanisms proposed by the RFC enable this, see [here](0000-ext-layout-traits.md). 78 | 79 | # Guide-level explanation 80 | [guide-level-explanation]: #guide-level-explanation 81 | 82 | ## Terminology & Concepts 83 | 84 | ### 📖 Transmutation 85 | **Transmutation** is the act of reinterpreting the bytes corresponding to a value of one type as if they corresponded to a different type. Concretely, we mean the behavior of this function: 86 | ```rust 87 | #[inline(always)] 88 | unsafe fn transmute(src: Src) -> Dst 89 | { 90 | #[repr(C)] 91 | union Transmute { 92 | src: ManuallyDrop, 93 | dst: ManuallyDrop, 94 | } 95 | 96 | ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst) 97 | } 98 | ``` 99 | 100 | ### 📖 Safer Transmutation 101 | By **safer transmutation** we mean: *what `where` bound could we add to `transmute` restricts its type parameters `Src` and `Dst` in ways that statically limit the function's misuse?* Our answer to this question will ensure that transmutations are, by default, *sound*, *safe* and *stable*. 102 | 103 | ### 📖 Soundness 104 | A transmutation is ***sound*** if the mere act of transmuting a value from one type to another is not unspecified or undefined behavior. 105 | 106 | ### 📖 Safety 107 | A sound transmutation is ***safe*** if *using* the transmuted value cannot violate memory safety. 108 | 109 | ### 📖 Stability 110 | A safe transmutation is ***stable*** if the authors of the source type and destination types have indicated that the layouts of those types is part of their libraries' stability guarantees. 111 | 112 | ## Concepts in Depth 113 | 114 | ***Disclaimer:** While the high-level definitions of transmutation soundness, safety and stability are a core component of this RFC, the detailed rules and examples in this section are **not**. We expect that the initial implementation of `TransmuteFrom` may initially be considerably less sophisticated than the examples in this section (and thus forbid valid transmutations). Nonetheless, this section explores nuanced cases of transmutation soundness and safety to demonstrate that the APIs we propose can grow to handle that nuance.* 115 | 116 | 117 | ### 📖 When is a transmutation sound? 118 | [sound transmutation]: #-when-is-a-transmutation-sound 119 | A transmutation is ***sound*** if the mere act of transmuting a value from one type to another is not unspecified or undefined behavior. 120 | 121 | #### Well-Defined Representation 122 | [`u8`]: core::u8 123 | [`f32`]: core::f32 124 | 125 | Transmutation is *always unsound* if it occurs between types with unspecified representations. 126 | 127 | Most of Rust's primitive types have specified representations. That is, the precise layout characteristics of [`u8`], [`f32`] is a documented and guaranteed aspect of those types. 128 | 129 | In contrast, most `struct` and `enum` types defined without an explicit `#[repr(C)]` attribute do ***not*** have well-specified layout characteristics. 130 | 131 | To ensure that types you've define are soundly transmutable, you almost always (with very few exceptions) must mark them with the `#[repr(C)]` attribute. 132 | 133 | #### Requirements on Owned Values 134 | [transmute-owned]: #requirements-on-owned-values 135 | 136 | Transmutations involving owned values must adhere to two rules to be sound. They must: 137 | * [preserve or broaden the bit validity][owned-validity], and 138 | * [preserve or shrink the size][owned-size]. 139 | 140 | ##### Preserve or Broaden Bit Validity 141 | [owned-validity]: #Preserve-or-Broaden-Bit-Validity 142 | [`NonZeroU8`]: https://doc.rust-lang.org/beta/core/num/struct.NonZeroU8.html 143 | 144 | The bits of any valid instance of the source type must be a bit-valid instance of the destination type. 145 | 146 | For example, we are permitted to transmute a `Bool` into a [`u8`]: 147 | ```rust 148 | #[derive(Default, PromiseTransmutableFrom, PromiseTransmutableInto)] 149 | #[repr(u8)] 150 | enum Bool { 151 | True = 1, 152 | False = 0, 153 | } 154 | 155 | let _ : u8 = Bool::True.transmute_into(); 156 | let _ : u8 = Bool::False.transmute_into(); 157 | ``` 158 | 159 | (Note: #[derive(PromiseTransmutableFrom, PromiseTransmutableInto)] annotation connotes that all aspects of Bool's layout are part of its library stability guarantee.) 160 | 161 | 162 | ...because all possible instances of `Bool` are also valid instances of [`u8`]. However, transmuting a [`u8`] into a `Bool` is forbidden: 163 | ```rust 164 | /* ⚠️ This example intentionally does not compile. */ 165 | let _ : Bool = u8::default().transmute_into(); // Compile Error! 166 | ``` 167 | ...because not all instances of [`u8`] are valid instances of `Bool`. 168 | 169 | Another example: While laying out certain types, Rust may insert padding bytes between the layouts of fields. In the below example `Padded` has two padding bytes, while `Packed` has none: 170 | ```rust 171 | #[repr(C)] 172 | #[derive(Default, PromiseTransmutableFrom, PromiseTransmutableInto)] 173 | struct Padded(pub u8, pub u16, pub u8); 174 | 175 | #[repr(C)] 176 | #[derive(Default, PromiseTransmutableFrom, PromiseTransmutableInto)] 177 | struct Packed(pub u16, pub u16, pub u16); 178 | 179 | assert_eq!(mem::size_of::(), mem::size_of::()); 180 | ``` 181 | 182 | We may safely transmute from `Packed` to `Padded`: 183 | ```rust 184 | let _ : Padded = Packed::default().transmute_into(); 185 | ``` 186 | ...but not from `Padded` to `Packed`: 187 | ```rust 188 | /* ⚠️ This example intentionally does not compile. */ 189 | let _ : Packed = Padded::default().transmute_into(); // Compile Error! 190 | ``` 191 | ...because doing so would expose two uninitialized padding bytes in `Padded` as if they were initialized bytes in `Packed`. 192 | 193 | ##### Preserve or Shrink Size 194 | [owned-size]: #Preserve-or-Shrink-Size 195 | 196 | It's completely sound to transmute into a type with fewer bytes than the source type; e.g.: 197 | ```rust 198 | let _ : [u8; 16] = [u8; 32]::default().transmute_into(); 199 | ``` 200 | This transmute truncates away the final sixteen bytes of the `[u8; 32]` value. 201 | 202 | A value may ***not*** be transmuted into a type of greater size, if doing so would expose uninitialized bytes as initialized: 203 | ```rust 204 | /* ⚠️ This example intentionally does not compile. */ 205 | let _ : [u8; 32] = [u8; 16]::default().transmute_into(); // Compile Error! 206 | ``` 207 | 208 | #### Requirements on References 209 | [transmute-references]: #requirements-on-references 210 | 211 | The [restrictions above that apply to transmuting owned values][transmute-owned] also apply to transmuting references. However, references carry a few additional restrictions. 212 | 213 | A [sound transmutation] must: 214 | - [preserve or shrink size][reference-size], 215 | - [preserve or relax alignment][reference-alignment], 216 | - [preserve or shrink lifetimes][reference-lifetimes], 217 | - [preserve or shrink uniqueness][reference-mutability], and 218 | - and if the destination type is a mutate-able reference, [preserve validity][reference-validity]. 219 | 220 | ##### Preserve or Shrink Size 221 | [reference-size]: #Preserve-or-Shrink-Size 222 | 223 | You may preserve or decrease the size of the referent type via transmutation: 224 | ```rust 225 | let _: &[u8; 3] = (&[0u8; 9]).transmute_into(); 226 | ``` 227 | 228 | However, you may **not**, under any circumstances, *increase* the size of the referent type: 229 | ```rust 230 | /* ⚠️ This example intentionally does not compile. */ 231 | let _: &[u8; 9] = (&[0u8; 3]).transmute_into(); // Compile Error! 232 | ``` 233 | ##### Preserve or Relax Alignment 234 | [reference-alignment]: #Preserve-or-Relax-Alignment 235 | 236 | Unaligned loads are undefined behavior. You may transmute a reference into reference of more relaxed alignment: 237 | ```rust 238 | let _: &[u8; 0] = (&[0u16; 0]).transmute_into(); 239 | ``` 240 | 241 | However, you may **not** transmute a reference into a reference of more-restrictive alignment: 242 | ```rust 243 | /* ⚠️ This example intentionally does not compile. */ 244 | let _: &[u16; 0] = (&[0u8; 0]).transmute_into(); // Compile Error! 245 | ``` 246 | 247 | ##### Preserve or Shrink Lifetimes 248 | [reference-lifetimes]: #Preserve-or-Shrink-Lifetimes 249 | 250 | You may transmute a reference into a reference of lesser lifetime: 251 | ```rust 252 | fn shrink<'a>() -> &'a u8 { 253 | static long : &'static u8 = &16; 254 | long.transmute_into() 255 | } 256 | ``` 257 | 258 | However, you may **not** transmute a reference into a reference of greater lifetime: 259 | ```rust 260 | /* ⚠️ This example intentionally does not compile. */ 261 | fn extend<'a>(short: &'a u8) -> &'static u8 { 262 | short.transmute_into() // Compile Error! 263 | } 264 | ``` 265 | 266 | ##### Preserve or Shrink Uniqueness 267 | [reference-mutability]: #Preserve-or-Shrink-Uniqueness 268 | 269 | You may preserve or decrease the uniqueness of a reference through transmutation: 270 | ```rust 271 | let _: &u8 = (&42u8).transmute_into(); 272 | let _: &u8 = (&mut 42u8).transmute_into(); 273 | ``` 274 | 275 | However, you may **not** transmute a shared reference into a unique reference: 276 | ```rust 277 | /* ⚠️ This example intentionally does not compile. */ 278 | let _: &mut u8 = (&42u8).transmute_into(); // Compile Error! 279 | ``` 280 | 281 | ##### Mutate-able References Must Preserve Validity 282 | [reference-validity]: #Mutate-able-References-Must-Preserve-Validity 283 | 284 | A mutate-able reference is: 285 | - all unique (i.e., `&mut T`) references 286 | - all shared (i.e., `&T`) references whose referent type contain any bytes produced by the contents of `UnsafeCell`. 287 | 288 | Unlike transmutations of owned values, the transmutation of a mutate-able reference may also not expand the bit-validity of the referenced type. For instance: 289 | ```rust 290 | /* ⚠️ This example intentionally does not compile. */ 291 | let mut x = NonZeroU8::new(42).unwrap(); 292 | { 293 | let y : &mut u8 = (&mut x).transmute_into(); // Compile Error! 294 | *y = 0; 295 | } 296 | 297 | let z : NonZeroU8 = x; 298 | ``` 299 | If this example did not produce a compile error, the value of `z` would not be a bit-valid instance of its type, [`NonZeroU8`]. 300 | 301 | 302 | 303 | ### 📖 When is a transmutation safe? 304 | A sound transmutation is ***safe*** if *using* the transmuted value safely cannot violate memory safety. Whereas soundness solely concerns the act of transmutation, *safety* is concerned with what might happen with a value *after* transmutation occurs. 305 | 306 | #### Implicit Constructability 307 | A struct or enum variant is *fully implicitly constructable* at a given location only if, at that location, that type can be instantiated via its *implicit constructor*, and its fields are also *implicitly constructable*. 308 | 309 | The *implicit constructor* of a struct or enum variant is the constructor Rust creates implicitly from its definition; e.g.: 310 | ```rust 311 | struct Point { 312 | x: T, 313 | y: T, 314 | } 315 | 316 | let p = Point { x: 4, y: 2 }; 317 | // ^^^^^^^^^^^^^^^^^^^^ An instance of `Point` is created here, via its implicit constructor. 318 | ``` 319 | 320 | Limiting implicit constructability is the fundamental mechanism with which type authors build safe abstractions for `unsafe` code, whose soundness is dependent on preserving invariants on fields. Usually, this takes the form of restricting the visibility of fields. For instance, consider the type `NonEmptySlice`, which enforces a validity constraint on its fields via its constructor: 321 | 322 | ```rust 323 | pub mod crate_a { 324 | 325 | #[repr(C)] 326 | pub struct NonEmptySlice<'a, T> { 327 | data: *const T, 328 | len: usize, 329 | lifetime: core::marker::PhantomData<&'a ()>, 330 | } 331 | 332 | impl<'a, T> NonEmptySlice<'a, T> { 333 | pub fn from_array(arr: &'a [T; N], len: usize) -> Self { 334 | assert!(len <= N); 335 | assert!(len > 0); 336 | Self { 337 | data: arr as *const T, 338 | len, 339 | lifetime: core::marker::PhantomData, 340 | } 341 | } 342 | 343 | pub fn first(&self) -> &'a T { 344 | unsafe { &*self.data } 345 | } 346 | } 347 | 348 | } 349 | ``` 350 | It is sound for `first` to be a *safe* method is because the `from_array` constructor ensures that `data` is safe to dereference, and because `from_array` is the *only* way to safely initialize `NonEmptySlice` outside of `crate_a` (note that `NonEmptySlice`'s fields are *not* `pub`). As a rule: any field that is not marked `pub` should be assumed to be private *because* it is subject to safety invariants. 351 | 352 | Unfortunately, field visibility modifiers are not a surefire indicator of whether a type is *fully* implicitly constructable. A type author may restrict the implicit constructability of a type even in situations where all fields of that type (*and all fields of those fields*) are `pub`; consider: 353 | ```rust 354 | pub mod crate_a { 355 | 356 | #[repr(C)] 357 | pub struct NonEmptySlice<'a, T>(pub private::NonEmptySliceInner<'a, T>); 358 | 359 | impl<'a, T> NonEmptySlice<'a, T> { 360 | pub fn from_array(arr: &'a [T; N], len: usize) -> Self { 361 | assert!(len <= N && len > 0); 362 | Self( 363 | private::NonEmptySliceInner { 364 | data: arr as *const T, 365 | len, 366 | lifetime: core::marker::PhantomData, 367 | } 368 | ) 369 | } 370 | 371 | pub fn first(&self) -> &'a T { 372 | unsafe { &*self.0.data } 373 | } 374 | } 375 | 376 | // introduce a private module to avoid `private_in_public` error (E0446): 377 | pub(crate) mod private { 378 | #[repr(C)] 379 | pub struct NonEmptySliceInner<'a, T> { 380 | pub data: *const T, 381 | pub len: usize, 382 | pub lifetime: core::marker::PhantomData<&'a ()>, 383 | } 384 | } 385 | 386 | } 387 | ``` 388 | In the above example, the definitions of both `NonEmptySlice` and its field `NonEmptySliceInner` are marked `pub`, and all fields of these types are marked `pub`. However, `NonEmptySlice` is *not* fully implicitly constructible outside of `crate_a`, because the module containing `NonEmptySliceInner` is not visibile outside of `crate_a`. 389 | 390 | #### Constructability and Transmutation 391 | Transmutation supplies a mechanism for constructing instances of a type *without* invoking its implicit constructor, nor any constructors defined by the type's author. 392 | 393 | In the previous examples, it would be *unsafe* to transmute `0u128` into `NonEmptySlice` outside `crate_a`, because subsequent *safe* use of that value (namely, calling `first`) would violate memory safety. (However, it's completely safe to transmute `NonEmptySlice` into a `u128`.) 394 | 395 | For transmutations where the destination type involves mutate-able references, the constructability of the source type is also relevant. Consider: 396 | ```rust 397 | /* ⚠️ This example intentionally does not compile. */ 398 | let arr = [0u8, 1u8, 2u8]; 399 | let mut x = NonEmptySlice::from_array(&arr, 2); 400 | { 401 | let y : &mut u128 = (&mut x).transmute_into(); // Compile Error! 402 | *y = 0u128; 403 | } 404 | 405 | let z : NonEmptySlice = x; 406 | ``` 407 | If this example did not produce a compile error, the value of `z` would not be a safe instance of its type, `NonEmptySlice`, because `z.first()` would dereference a null pointer. 408 | 409 | ### 📖 When is a transmutation stable? 410 | [stability]: #-when-is-a-transmutation-stable 411 | 412 | Since the soundness and safety of a transmutation is affected by the layouts of the source and destination types, changes to those types' layouts may cause code which previously compiled to produce errors. In other words, transmutation causes a type's layout to become part of that type's API for the purposes of SemVer stability. 413 | 414 | The question is, then: *how can the author of a type reason about transmutations they did not write, from-or-to types they did not write?* We address this problem by introducing two traits which both allow an author to opt-in to stability guarantees for their types, and allow third-parties to reason at compile-time about what guarantees are provided for such types. 415 | 416 | #### `PromiseTransmutableFrom` and `PromiseTransmutableInto` 417 | 418 | You may declare the stability guarantees of your type by implementing one or both of two traits: 419 | ```rust 420 | pub trait PromiseTransmutableFrom 421 | where 422 | Self::Archetype: PromiseTransmutableFrom 423 | { 424 | type Archetype: TransmuteInto 425 | } 426 | 427 | pub trait PromiseTransmutableInto 428 | where 429 | Self::Archetype: PromiseTransmutableInto, 430 | { 431 | type Archetype: TransmuteFrom 432 | } 433 | ``` 434 | 435 | To implement each of these traits, you must specify an `Archetype`. An `Archetype` is a type whose layout exemplifies the extremities of your stability promise (i.e., the least/most constrained type for which it is valid to transmute your type into/from). 436 | 437 | By implementing `PromiseTransmutableFrom`, you promise that your type is guaranteed to be safely transmutable *from* `PromiseTransmutableFrom::Archetype`. Conversely, by implementing `PromiseTransmutableInto`, you promise that your type is guaranteed to be safely transmutable *into* `PromiseTransmutableInto::Archetype`. 438 | 439 | You are free to change the layout of your type however you like between minor crate versions so long as that change does not violates these promises. These two traits are capable of expressing simple and complex stability guarantees. 440 | 441 | #### Stability & Transmutation 442 | Together with the `PromiseTransmutableFrom` and `PromiseTransmutableInto` traits, this impl of `TransmuteFrom` constitutes the formal definition of transmutation stability: 443 | ```rust 444 | unsafe impl TransmuteFrom for Dst 445 | where 446 | Src: PromiseTransmutableInto, 447 | Dst: PromiseTransmutableFrom, 448 | 449 | Dst::Archetype: TransmuteFrom 450 | {} 451 | ``` 452 | Why is this safe? Can we really safely judge whether `Dst` is transmutable from `Src` by assessing the transmutability of two different types? Yes! Transmutability is *transitive*. Concretely, if we can safely transmute: 453 | - `Src` to `Src::Archetype` (enforced by `Src: PromiseTransmutableInto`), and 454 | - `Dst::Archetype` to `Dst` (enforced by `Dst: PromiseTransmutableFrom`), and 455 | - `Src::Archetype` to `Dst::Archetype` (enforced by `Dst::Archetype: TransmuteFrom`), 456 | 457 | ...then it follows that we can safely transmute `Src` to `Dst` in three steps: 458 | 1. we transmute `Src` to `Src::Archetype`, 459 | 2. we transmute `Src::Archetype` to `Dst::Archetype`, 460 | 3. we transmute `Dst::Archetype` to `Dst`. 461 | 462 | #### Common Use-Case: As-Stable-As-Possible 463 | [stability-common]: #common-use-case-as-stable-as-possible 464 | To promise that all transmutations which are currently safe for your type will remain so in the future, simply annotate your type with: 465 | ```rust 466 | #[derive(PromiseTransmutableFrom, PromiseTransmutableInto)] 467 | #[repr(C)] 468 | pub struct Foo(pub Bar, pub Baz); 469 | ``` 470 | This expands to: 471 | ```rust 472 | #[repr(C)] 473 | pub struct Foo(pub Bar, pub Baz); 474 | 475 | /// Generated `PromiseTransmutableFrom` for `Foo` 476 | const _: () = { 477 | use core::transmute::stability::PromiseTransmutableFrom; 478 | 479 | #[repr(C)] 480 | pub struct TransmutableFromArchetype( 481 | pub ::Archetype, 482 | pub ::Archetype, 483 | ); 484 | 485 | impl PromiseTransmutableFrom for TransmutableFromArchetype { 486 | type Archetype = Self; 487 | } 488 | 489 | impl PromiseTransmutableFrom for Foo { 490 | type Archetype = TransmutableFromArchetype; 491 | } 492 | }; 493 | 494 | /// Generated `PromiseTransmutableInto` for `Foo` 495 | const _: () = { 496 | use core::transmute::stability::PromiseTransmutableInto; 497 | 498 | #[repr(C)] 499 | pub struct TransmutableIntoArchetype( 500 | pub ::Archetype, 501 | pub ::Archetype, 502 | ); 503 | 504 | impl PromiseTransmutableFrom for TransmutableIntoArchetype { 505 | type Archetype = Self; 506 | } 507 | 508 | impl PromiseTransmutableInto for Foo { 509 | type Archetype = TransmutableIntoArchetype; 510 | } 511 | }; 512 | ``` 513 | Since deriving *both* of these traits together is, by far, the most common use-case, we [propose][extension-promisetransmutable-shorthand] `#[derive(PromiseTransmutable)]` as an ergonomic shortcut. 514 | 515 | 516 | #### Uncommon Use-Case: Weak Stability Guarantees 517 | [stability-uncommon]: #uncommon-use-case-weak-stability-guarantees 518 | 519 | We also can specify *custom* `Archetype`s to finely constrain the set of transmutations we are willing to make stability promises for. Consider, for instance, if we want to leave ourselves the future leeway to change the alignment of a type `Foo` without making a SemVer major change: 520 | ```rust 521 | #[repr(C)] 522 | pub struct Foo(pub Bar, pub Baz); 523 | ``` 524 | The alignment of `Foo` affects transmutability of `&Foo`. A `&Foo` cannot be safely transmuted from a `&Bar` if the alignment requirements of `Foo` exceed those of `Bar`. If we don't want to promise that `&Foo` is stably transmutable from virtually *any* `Bar`, we simply make `Foo`'s `PromiseTransmutableFrom::Archetype` a type with maximally strict alignment requirements: 525 | ```rust 526 | const _: () = { 527 | use core::transmute::stability::PromiseTransmutableFrom; 528 | 529 | #[repr(C, align(536870912))] 530 | pub struct TransmutableFromArchetype( 531 | pub ::Archetype, 532 | pub ::Archetype, 533 | ); 534 | 535 | impl PromiseTransmutableFrom for TransmutableFromArchetype { 536 | type Archetype = Self; 537 | } 538 | 539 | impl PromiseTransmutableFrom for Foo { 540 | type Archetype = TransmutableFromArchetype; 541 | } 542 | }; 543 | ``` 544 | Conversely, a `&Foo` cannot be safely transmuted *into* a `&Bar` if the alignment requirements of `Bar` exceed those of `Foo`. We reduce this set of stable transmutations by making `PromiseTransmutableFrom::Archetype` a type with minimal alignment requirements: 545 | ```rust 546 | const _: () = { 547 | use core::transmute::stability::PromiseTransmutableInto; 548 | 549 | #[repr(C, packed(1))] 550 | pub struct TransmutableIntoArchetype( 551 | pub ::Archetype, 552 | pub ::Archetype, 553 | ); 554 | 555 | impl PromiseTransmutableInto for TransmutableIntoArchetype { 556 | type Archetype = Self; 557 | } 558 | 559 | impl PromiseTransmutableInto for Foo { 560 | type Archetype = TransmutableIntoArchetype; 561 | } 562 | }; 563 | ``` 564 | Given these two stability promises, we are free to modify the alignment of `Foo` in SemVer-minor changes without running any risk of breaking dependent crates. 565 | 566 | 567 | ## Mechanisms of Transmutation 568 | 569 | Two traits provide mechanisms for transmutation between types: 570 | ```rust 571 | // this trait is implemented automagically by the compiler 572 | #[lang = "transmute_from"] 573 | pub unsafe trait TransmuteFrom 574 | where 575 | Neglect: TransmuteOptions, 576 | { 577 | #[inline(always)] 578 | fn transmute_from(src: Src) -> Self 579 | where 580 | Src: Sized, 581 | Self: Sized, 582 | Neglect: SafeTransmuteOptions, 583 | { 584 | unsafe { Self::unsafe_transmute_from(src) } 585 | } 586 | 587 | #[inline(always)] 588 | unsafe fn unsafe_transmute_from(src: Src) -> Self 589 | where 590 | Src: Sized, 591 | Self: Sized, 592 | Neglect: TransmuteOptions, 593 | { 594 | use core::mem::ManuallyDrop; 595 | 596 | #[repr(C)] 597 | union Transmute { 598 | src: ManuallyDrop, 599 | dst: ManuallyDrop, 600 | } 601 | 602 | unsafe { 603 | ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst) 604 | } 605 | } 606 | } 607 | 608 | // implemented in terms of `TransmuteFrom` 609 | pub unsafe trait TransmuteInto 610 | where 611 | Neglect: TransmuteOptions, 612 | { 613 | fn transmute_into(self) -> Dst 614 | where 615 | Self: Sized, 616 | Dst: Sized, 617 | Neglect: SafeTransmuteOptions; 618 | 619 | unsafe fn unsafe_transmute_into(self) -> Dst 620 | where 621 | Self: Sized, 622 | Dst: Sized, 623 | Neglect: TransmuteOptions; 624 | } 625 | 626 | unsafe impl TransmuteInto for Src 627 | where 628 | Src: ?Sized, 629 | Dst: ?Sized + TransmuteFrom, 630 | Neglect: TransmuteOptions, 631 | { 632 | ... 633 | } 634 | ``` 635 | 636 | In the above definitions, `Src` represents the source type of the transmutation, `Dst` represents the destination type of the transmutation, and `Neglect` is a parameter that [encodes][options] which static checks the compiler ought to neglect when considering if a transmutation is valid. The default value of `Neglect` is `()`, which reflects that, by default, the compiler does not neglect *any* static checks. 637 | 638 | ### Neglecting Static Checks 639 | [options]: #Neglecting-Static-Checks 640 | 641 | The default value of the `Neglect` parameter, `()`, statically forbids transmutes that are unsafe, unsound, or unstable. However, you may explicitly opt-out of some static checks: 642 | 643 | | Transmute Option | Compromises | Usable With | 644 | |---------------------|-------------|---------------------------------------------------------| 645 | | `NeglectStabilty` | Stability | `transmute_{from,into}`, `unsafe_transmute_{from,into}` | 646 | | `NeglectAlignment` | Safety | `unsafe_transmute_{from,into}` | 647 | | `NeglectValidity` | Soundness | `unsafe_transmute_{from,into}` | 648 | 649 | `NeglectStabilty` implements the `SafeTransmuteOptions` and `TransmuteOptions` marker traits, as it can be used in both safe and unsafe code. The selection of multiple options is encoded by grouping them as a tuple; e.g., `(NeglectAlignment, NeglectValidity)` is a selection of both the `NeglectAlignment` and `NeglectValidity` options. 650 | 651 | We introduce two marker traits which serve to group together the options that may be used with safe transmutes, and those which may be used with `unsafe` transmutes: 652 | ```rust 653 | pub trait SafeTransmuteOptions: private::Sealed 654 | {} 655 | 656 | pub trait TransmuteOptions: SafeTransmuteOptions 657 | {} 658 | 659 | impl SafeTransmuteOptions for () {} 660 | impl TransmuteOptions for () {} 661 | ``` 662 | 663 | #### `NeglectStability` 664 | [`NeglectStability`]: #neglectstability 665 | 666 | By default, `TransmuteFrom` and `TransmuteInto`'s methods require that the [layouts of the source and destination types are SemVer-stable][stability]. The `NeglectStability` option disables this requirement. 667 | ```rust 668 | pub struct NeglectStability; 669 | 670 | impl SafeTransmuteOptions for NeglectStability {} 671 | impl TransmuteOptions for NeglectStability {} 672 | ``` 673 | 674 | Prior to the adoption of the [stability declaration traits][stability], crate authors documented the layout guarantees of their types with doc comments. The `TransmuteFrom` and `TransmuteInto` traits and methods may be used with these types by requesting that the stability check is neglected; for instance: 675 | 676 | ```rust 677 | fn serialize(val : LibraryType, dst: W) -> std::io::Result<()> 678 | where 679 | LibraryType: TransmuteInto<[u8; size_of::()], NeglectStability> 680 | { 681 | ... 682 | } 683 | ``` 684 | 685 | Neglecting stability over-eagerly cannot cause unsoundness or unsafety. For this reason, it is the only transmutation option available on the safe methods `transmute_from` and `transmute_into`. However, neglecting stability over-eagerly may cause your code to cease compiling if the authors of the source and destination types make changes that affect their layout. 686 | 687 | By using the `NeglectStability` option to transmute types you do not own, you are committing to ensure that your reliance on these types' layouts is consistent with their documented stability guarantees. 688 | 689 | #### `NeglectAlignment` 690 | [ext-ref-casting]: #NeglectAlignment 691 | 692 | By default, `TransmuteFrom` and `TransmuteInto`'s methods require that, when transmuting references, the minimum alignment of the destination's referent type is no greater than the minimum alignment of the source's referent type. The `NeglectAlignment` option disables this requirement. 693 | ```rust 694 | pub struct NeglectAlignment; 695 | 696 | impl TransmuteOptions for NeglectAlignment {} 697 | ``` 698 | 699 | By using the `NeglectAlignment` option, you are committing to ensure that the transmuted reference satisfies the alignment requirements of the destination's referent type. For instance: 700 | ```rust 701 | /// Try to convert a `&T` into `&U`. 702 | /// 703 | /// This produces `None` if the referent isn't appropriately 704 | /// aligned, as required by the destination type. 705 | pub fn try_cast_ref<'t, 'u, T, U>(src: &'t T) -> Option<&'u U> 706 | where 707 | &'t T: TransmuteInto<&'u U, NeglectAlignment>, 708 | { 709 | if (src as *const T as usize) % align_of::() != 0 { 710 | None 711 | } else { 712 | // Safe because we dynamically enforce the alignment 713 | // requirement, whose static check we chose to neglect. 714 | Some(unsafe { src.unsafe_transmute_into() }) 715 | } 716 | } 717 | ``` 718 | 719 | #### `NeglectValidity` 720 | By default, `TransmuteFrom` and `TransmuteInto`'s methods require that all instantiations of the source type are guaranteed to be valid instantiations of the destination type. This precludes transmutations which *might* be valid depending on the source value: 721 | ```rust 722 | #[derive(PromiseTransmutableFrom, PromiseTransmutableInto)] 723 | #[repr(u8)] 724 | enum Bool { 725 | True = 1, 726 | False = 0, 727 | } 728 | 729 | /* ⚠️ This example intentionally does not compile. */ 730 | let _ : Bool = some_u8_value.transmute_into(); // Compile Error! 731 | ``` 732 | The `NeglectValidity` option disables this check. 733 | ```rust 734 | pub struct NeglectValidity; 735 | 736 | impl TransmuteOptions for NeglectValidity {} 737 | ``` 738 | 739 | By using the `NeglectValidity` option, you are committing to ensure dynamically source value is a valid instance of the destination type. For instance: 740 | ```rust 741 | #[derive(PromiseTransmutableFrom, PromiseTransmutableInto)] 742 | #[repr(u8)] 743 | enum Bool { 744 | True = 1, 745 | False = 0, 746 | } 747 | 748 | pub trait TryIntoBool 749 | { 750 | fn try_into_bool(self) -> Option; 751 | } 752 | 753 | impl TryIntoBool for T 754 | where 755 | T: TransmuteInto, 756 | u8: TransmuteInto 757 | { 758 | fn try_into_bool(self) -> Option { 759 | let val: u8 = self.transmute_into(); 760 | 761 | if val > 1 { 762 | None 763 | } else { 764 | // Safe, because we've first verified that 765 | // `val` is a bit-valid instance of a boolean. 766 | Some(unsafe {val.unsafe_transmute_into()}) 767 | } 768 | } 769 | } 770 | ``` 771 | 772 | Even with `NeglectValidity`, the compiler will statically reject transmutations that cannot possibly be valid: 773 | ```rust 774 | #[derive(PromiseTransmutableInto)] 775 | #[repr(C)] enum Foo { A = 24 } 776 | 777 | #[derive(PromiseTransmutableFrom)] 778 | #[repr(C)] enum Bar { Z = 42 } 779 | 780 | let _ = ::unsafe_transmute_from(Foo::N) // Compile error! 781 | ``` 782 | 783 | # Reference-level explanation 784 | [reference-level-explanation]: #reference-level-explanation 785 | 786 | 787 | ## Implementation Guidance 788 | The *only* item defined by this RFC requiring special compiler support is `TransmuteFrom`. To realize this RFC's proposal of safe transmutation between different types, this item will require compiler support. However, the *most* minimal acceptable implementation of `TransmuteFrom` can be achieved entirely in-language: 789 | 790 | ```rust 791 | /// A type is transmutable into itself. 792 | unsafe impl TransmuteFrom for T 793 | where 794 | Neglect: TransmuteOptions 795 | {} 796 | 797 | /// A transmutation is *stable* if... 798 | unsafe impl TransmuteFrom for Dst 799 | where 800 | Src: PromiseTransmutableInto, 801 | Dst: PromiseTransmutableFrom, 802 | ::Archetype: 803 | TransmuteFrom< 804 | ::Archetype, 805 | NeglectStability 806 | > 807 | {} 808 | ``` 809 | This [minimal implementation][minimal-impl] is sufficient for convincing the compiler to accept basic stability declarations, such as those of Rust's primitive types. It is *insufficient* for making the compiler accept transmutations between *different* types (and, consequently, complex stability declarations). Implementers should use this as a starting point. 810 | 811 | ### Listing for Initial, Minimal Implementation 812 | [minimal-impl]: #Listing-for-Initial-Minimal-Implementation 813 | This listing is both a minimal implementation of this RFC (excepting the automatic derives) and the **canonical specification** of this RFC's API surface ([playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=1ff1700e6dba595f1e600d20da5d6387)): 814 | ```rust 815 | #![feature(untagged_unions,const_fn,const_fn_union)] // for the impl of transmute free functions 816 | #![feature(const_generics)] // for stability declarations on `[T; N]` 817 | #![feature(decl_macro)] // for stub implementations of derives 818 | #![feature(never_type)] // for stability declarations on `!` 819 | #![allow(warnings)] 820 | 821 | /// Transmutation conversions. 822 | // suggested location: `core::convert` 823 | pub mod transmute { 824 | 825 | use {options::*, stability::*}; 826 | 827 | /// Reinterprets the bits of a value of one type as another type, safely. 828 | /// 829 | /// Use `()` for `Neglect` if you do not wish to neglect any static checks. 830 | #[inline(always)] 831 | pub const fn safe_transmute(src: Src) -> Dst 832 | where 833 | Dst: TransmuteFrom, 834 | Neglect: SafeTransmuteOptions 835 | { 836 | unsafe { unsafe_transmute::(src) } 837 | } 838 | 839 | /// Reinterprets the bits of a value of one type as another type, potentially unsafely. 840 | /// 841 | /// The onus is on you to ensure that calling this method is safe. 842 | #[inline(always)] 843 | pub const unsafe fn unsafe_transmute(src: Src) -> Dst 844 | where 845 | Dst: TransmuteFrom, 846 | Neglect: TransmuteOptions 847 | { 848 | use core::mem::ManuallyDrop; 849 | 850 | #[repr(C)] 851 | union Transmute { 852 | src: ManuallyDrop, 853 | dst: ManuallyDrop, 854 | } 855 | 856 | unsafe { 857 | ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst) 858 | } 859 | } 860 | 861 | /// `Self: TransmuteInto 865 | where 866 | Neglect: TransmuteOptions, 867 | { 868 | /// Reinterpret the bits of a value of one type as another type, safely. 869 | fn transmute_into(self) -> Dst 870 | where 871 | Self: Sized, 872 | Dst: Sized, 873 | Neglect: SafeTransmuteOptions; 874 | 875 | /// Reinterpret the bits of a value of one type as another type, potentially unsafely. 876 | /// 877 | /// The onus is on you to ensure that calling this method is safe. 878 | unsafe fn unsafe_transmute_into(self) -> Dst 879 | where 880 | Self: Sized, 881 | Dst: Sized, 882 | Neglect: TransmuteOptions; 883 | } 884 | 885 | unsafe impl TransmuteInto for Src 886 | where 887 | Src: ?Sized, 888 | Dst: ?Sized + TransmuteFrom, 889 | Neglect: TransmuteOptions, 890 | { 891 | #[inline(always)] 892 | fn transmute_into(self) -> Dst 893 | where 894 | Self: Sized, 895 | Dst: Sized, 896 | Neglect: SafeTransmuteOptions, 897 | { 898 | Dst::transmute_from(self) 899 | } 900 | 901 | #[inline(always)] 902 | unsafe fn unsafe_transmute_into(self) -> Dst 903 | where 904 | Self: Sized, 905 | Dst: Sized, 906 | Neglect: TransmuteOptions, 907 | { 908 | unsafe { Dst::unsafe_transmute_from(self) } 909 | } 910 | } 911 | 912 | /// `Self: TransmuteInto 916 | where 917 | Neglect: TransmuteOptions, 918 | { 919 | /// Reinterpret the bits of a value of one type as another type, safely. 920 | #[inline(always)] 921 | fn transmute_from(src: Src) -> Self 922 | where 923 | Src: Sized, 924 | Self: Sized, 925 | Neglect: SafeTransmuteOptions, 926 | { 927 | unsafe { Self::unsafe_transmute_from(src) } 928 | } 929 | 930 | /// Reinterpret the bits of a value of one type as another type, potentially unsafely. 931 | /// 932 | /// The onus is on you to ensure that calling this function is safe. 933 | #[inline(always)] 934 | unsafe fn unsafe_transmute_from(src: Src) -> Self 935 | where 936 | Src: Sized, 937 | Self: Sized, 938 | Neglect: TransmuteOptions, 939 | { 940 | unsafe_transmute::(src) 941 | } 942 | } 943 | 944 | /// A type is always transmutable from itself. 945 | // This impl will be replaced with a compiler-supported for arbitrary source and destination types. 946 | unsafe impl TransmuteFrom for T {} 947 | 948 | /// A type is *stably* transmutable if... 949 | unsafe impl TransmuteFrom for Dst 950 | where 951 | Src: PromiseTransmutableInto, 952 | Dst: PromiseTransmutableFrom, 953 | ::Archetype: 954 | TransmuteFrom< 955 | ::Archetype, 956 | NeglectStability 957 | > 958 | {} 959 | 960 | /// Traits for declaring the SemVer stability of types. 961 | pub mod stability { 962 | 963 | use super::{TransmuteFrom, TransmuteInto, options::NeglectStability}; 964 | 965 | /// Declare that transmuting `Self` into `Archetype` is SemVer-stable. 966 | pub trait PromiseTransmutableInto 967 | where 968 | Self::Archetype: PromiseTransmutableInto 969 | { 970 | /// The `Archetype` must be safely transmutable from `Self`. 971 | type Archetype: TransmuteFrom; 972 | } 973 | 974 | /// Declare that transmuting `Self` from `Archetype` is SemVer-stable. 975 | pub trait PromiseTransmutableFrom 976 | where 977 | Self::Archetype: PromiseTransmutableFrom 978 | { 979 | /// The `Archetype` must be safely transmutable into `Self`. 980 | type Archetype: TransmuteInto; 981 | } 982 | 983 | 984 | /// Derive macro generating an impl of the trait `PromiseTransmutableInto`. 985 | //#[rustc_builtin_macro] 986 | pub macro PromiseTransmutableInto($item:item) { 987 | /* compiler built-in */ 988 | } 989 | 990 | /// Derive macro generating an impl of the trait `PromiseTransmutableFrom`. 991 | //#[rustc_builtin_macro] 992 | pub macro PromiseTransmutableFrom($item:item) { 993 | /* compiler built-in */ 994 | } 995 | 996 | 997 | impl PromiseTransmutableInto for ! {type Archetype = Self;} 998 | impl PromiseTransmutableFrom for ! {type Archetype = Self;} 999 | 1000 | impl PromiseTransmutableInto for () {type Archetype = Self;} 1001 | impl PromiseTransmutableFrom for () {type Archetype = Self;} 1002 | 1003 | impl PromiseTransmutableInto for f32 {type Archetype = Self;} 1004 | impl PromiseTransmutableFrom for f32 {type Archetype = Self;} 1005 | impl PromiseTransmutableInto for f64 {type Archetype = Self;} 1006 | impl PromiseTransmutableFrom for f64 {type Archetype = Self;} 1007 | 1008 | impl PromiseTransmutableInto for i8 {type Archetype = Self;} 1009 | impl PromiseTransmutableFrom for i8 {type Archetype = Self;} 1010 | impl PromiseTransmutableInto for i16 {type Archetype = Self;} 1011 | impl PromiseTransmutableFrom for i16 {type Archetype = Self;} 1012 | impl PromiseTransmutableInto for i32 {type Archetype = Self;} 1013 | impl PromiseTransmutableFrom for i32 {type Archetype = Self;} 1014 | impl PromiseTransmutableInto for i64 {type Archetype = Self;} 1015 | impl PromiseTransmutableFrom for i64 {type Archetype = Self;} 1016 | impl PromiseTransmutableInto for i128 {type Archetype = Self;} 1017 | impl PromiseTransmutableFrom for i128 {type Archetype = Self;} 1018 | impl PromiseTransmutableInto for isize {type Archetype = Self;} 1019 | impl PromiseTransmutableFrom for isize {type Archetype = Self;} 1020 | 1021 | impl PromiseTransmutableInto for u8 {type Archetype = Self;} 1022 | impl PromiseTransmutableFrom for u8 {type Archetype = Self;} 1023 | impl PromiseTransmutableInto for u16 {type Archetype = Self;} 1024 | impl PromiseTransmutableFrom for u16 {type Archetype = Self;} 1025 | impl PromiseTransmutableInto for u32 {type Archetype = Self;} 1026 | impl PromiseTransmutableFrom for u32 {type Archetype = Self;} 1027 | impl PromiseTransmutableInto for u64 {type Archetype = Self;} 1028 | impl PromiseTransmutableFrom for u64 {type Archetype = Self;} 1029 | impl PromiseTransmutableInto for u128 {type Archetype = Self;} 1030 | impl PromiseTransmutableFrom for u128 {type Archetype = Self;} 1031 | impl PromiseTransmutableInto for usize {type Archetype = Self;} 1032 | impl PromiseTransmutableFrom for usize {type Archetype = Self;} 1033 | 1034 | use core::marker::PhantomData; 1035 | impl PromiseTransmutableInto for PhantomData { type Archetype = Self; } 1036 | impl PromiseTransmutableFrom for PhantomData { type Archetype = Self; } 1037 | 1038 | 1039 | impl PromiseTransmutableInto for [T; N] 1040 | where 1041 | T: PromiseTransmutableInto, 1042 | [T::Archetype; N] 1043 | : TransmuteFrom 1044 | + PromiseTransmutableInto, 1045 | { 1046 | type Archetype = [T::Archetype; N]; 1047 | } 1048 | 1049 | impl PromiseTransmutableFrom for [T; N] 1050 | where 1051 | T: PromiseTransmutableFrom, 1052 | [T::Archetype; N] 1053 | : TransmuteInto 1054 | + PromiseTransmutableFrom, 1055 | { 1056 | type Archetype = [T::Archetype; N]; 1057 | } 1058 | 1059 | 1060 | impl PromiseTransmutableInto for *const T 1061 | where 1062 | T: PromiseTransmutableInto, 1063 | *const T::Archetype 1064 | : TransmuteFrom 1065 | + PromiseTransmutableInto, 1066 | { 1067 | type Archetype = *const T::Archetype; 1068 | } 1069 | 1070 | impl PromiseTransmutableFrom for *const T 1071 | where 1072 | T: PromiseTransmutableFrom, 1073 | *const T::Archetype 1074 | : TransmuteInto 1075 | + PromiseTransmutableFrom, 1076 | { 1077 | type Archetype = *const T::Archetype; 1078 | } 1079 | 1080 | 1081 | impl PromiseTransmutableInto for *mut T 1082 | where 1083 | T: PromiseTransmutableInto, 1084 | *mut T::Archetype 1085 | : TransmuteFrom 1086 | + PromiseTransmutableInto, 1087 | { 1088 | type Archetype = *mut T::Archetype; 1089 | } 1090 | 1091 | impl PromiseTransmutableFrom for *mut T 1092 | where 1093 | T: PromiseTransmutableFrom, 1094 | *mut T::Archetype 1095 | : TransmuteInto 1096 | + PromiseTransmutableFrom, 1097 | { 1098 | type Archetype = *mut T::Archetype; 1099 | } 1100 | 1101 | 1102 | impl<'a, T: ?Sized> PromiseTransmutableInto for &'a T 1103 | where 1104 | T: PromiseTransmutableInto, 1105 | &'a T::Archetype 1106 | : TransmuteFrom<&'a T, NeglectStability> 1107 | + PromiseTransmutableInto, 1108 | { 1109 | type Archetype = &'a T::Archetype; 1110 | } 1111 | 1112 | impl<'a, T: ?Sized> PromiseTransmutableFrom for &'a T 1113 | where 1114 | T: PromiseTransmutableFrom, 1115 | &'a T::Archetype 1116 | : TransmuteInto<&'a T, NeglectStability> 1117 | + PromiseTransmutableFrom, 1118 | { 1119 | type Archetype = &'a T::Archetype; 1120 | } 1121 | 1122 | impl<'a, T: ?Sized> PromiseTransmutableInto for &'a mut T 1123 | where 1124 | T: PromiseTransmutableInto, 1125 | &'a mut T::Archetype 1126 | : TransmuteFrom<&'a mut T, NeglectStability> 1127 | + PromiseTransmutableInto, 1128 | { 1129 | type Archetype = &'a mut T::Archetype; 1130 | } 1131 | 1132 | impl<'a, T: ?Sized> PromiseTransmutableFrom for &'a mut T 1133 | where 1134 | T: PromiseTransmutableFrom, 1135 | &'a mut T::Archetype 1136 | : TransmuteInto<&'a mut T, NeglectStability> 1137 | + PromiseTransmutableFrom, 1138 | { 1139 | type Archetype = &'a mut T::Archetype; 1140 | } 1141 | } 1142 | 1143 | /// Static checks that may be neglected when determining if a type is `TransmuteFrom` some other type. 1144 | pub mod options { 1145 | 1146 | /// Options that may be used with safe transmutations. 1147 | pub trait SafeTransmuteOptions: TransmuteOptions {} 1148 | 1149 | /// Options that may be used with unsafe transmutations. 1150 | pub trait TransmuteOptions: private::Sealed {} 1151 | 1152 | impl SafeTransmuteOptions for () {} 1153 | impl TransmuteOptions for () {} 1154 | 1155 | /// Neglect the stability check of `TransmuteFrom`. 1156 | pub struct NeglectStability; 1157 | 1158 | // Uncomment this if/when constructibility is fully implemented: 1159 | // impl SafeTransmuteOptions for NeglectStability {} 1160 | impl TransmuteOptions for NeglectStability {} 1161 | 1162 | // prevent third-party implementations of `TransmuteOptions` 1163 | mod private { 1164 | use super::*; 1165 | 1166 | pub trait Sealed {} 1167 | 1168 | impl Sealed for () {} 1169 | impl Sealed for NeglectStability {} 1170 | } 1171 | } 1172 | } 1173 | ``` 1174 | 1175 | ### Towards an Initial, Smart Implementation 1176 | 1177 | To support transmutations between different types, implementers of this RFC should begin by defining a `transmute_from` lang item to annotate libcore's definition of `TransmuteFrom`. Whether `TransmuteFrom` is implemented for a given type and parameters shall be determined within the implementation of the type system (à la [`Sized`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html#method.is_sized) and [`Freeze`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html#method.is_freeze)). 1178 | 1179 | This initial smart implementation may be made simpler by: 1180 | - *not* supporting enums 1181 | - *not* supporting unions 1182 | - *not* supporting `Neglect` parameters besides `()` and `NeglectStability` 1183 | - simplifying constructability 1184 | 1185 | #### Simplifying Constructability 1186 | The safety property of constructability defined in the guidance-level explanation of this RFC describes a platonic ideal of the property. 1187 | 1188 | However, we recognize that this definition poses implementation challenges: In our definition of constructability, answering the question of whether a struct or enum variant is constructible depends on *where* that question is being asked. Consequently, answering whether a given type `Src` is `TransmutableInto` a given type `Dst` will depend on *where* that question is posed. 1189 | 1190 | We recommend adopting a simplified definition of *constructability*: a type is *constructible* if its fields are marked `pub`, and those fields are constructible. With this definition, answering the question of whether a type is constructible does *not* depend on where the question is asked: we do not examine the visibility of the involved types. 1191 | 1192 | Unfortunately, with no other actions taken, this simplified definition comes... 1193 | 1194 | ##### ...at the Cost of Safety 1195 | This definition is *usually* sufficient for ensuring safety: it is *generally* an error to expose a private type in a public type signature. However, these errors may be circumvented using the public-type-in-private-module trick: 1196 | ```rust 1197 | pub mod crate_a { 1198 | 1199 | #[repr(C)] 1200 | pub struct NonEmptySlice<'a, T>(pub private::NonEmptySliceInner<'a, T>); 1201 | 1202 | impl<'a, T> NonEmptySlice<'a, T> { 1203 | pub fn from_array(arr: &'a [T; N], len: usize) -> Self { 1204 | assert!(len <= N && len > 0); 1205 | Self( 1206 | private::NonEmptySliceInner { 1207 | data: arr as *const T, 1208 | len, 1209 | lifetime: core::marker::PhantomData, 1210 | } 1211 | ) 1212 | } 1213 | 1214 | pub fn first(&self) -> &'a T { 1215 | unsafe { &*self.0.data } 1216 | } 1217 | } 1218 | 1219 | // introduce a private module to avoid `private_in_public` error (E0446): 1220 | pub(crate) mod private { 1221 | #[repr(C)] 1222 | pub struct NonEmptySliceInner<'a, T> { 1223 | pub data: *const T, 1224 | pub len: usize, 1225 | pub lifetime: core::marker::PhantomData<&'a ()>, 1226 | } 1227 | } 1228 | 1229 | } 1230 | ``` 1231 | With this simplified definition of constructability, it is possible for a third-party to define a *safe* constructor of `NonEmptySlice` that produces a value which is *unsafe* to use: 1232 | ```rust 1233 | pub evil_constructor(src: T) -> NonEmptySlice<'static, u8> 1234 | where 1235 | T: TransmuteInto, NeglectStability>, 1236 | { 1237 | src.transmute_into() 1238 | } 1239 | 1240 | evil_constructor(0u128).first() // muahaha! 1241 | ``` 1242 | 1243 | The above code is "safe" because our simplified definition of constructability fails to recognize this pattern of encapsulation, and because `NeglectStability` is a `SafeTransmutationOption`. 1244 | 1245 | The intent of `NeglectStability` is to permit the safe transmutation of types that predate the stabilization of the stability declaration traits. It also provides a convenient escape-hatch for type authors to neglect the stability of transmutations of their *own* types, without sacrificing safety. `NeglectStability` is a `SafeTransmutationOption` because, in principle, neglecting stability does not diminish safety. Our simplified definition of constructability violates this principle. 1246 | 1247 | By temporarily sacrificing these goals, we may preserve safety solely... 1248 | 1249 | ##### ...at the Cost of `NeglectStability` 1250 | We may preserve safety by demoting `NeglectStability` to `UnsafeTransmutationOption`-status. 1251 | 1252 | In doing so, a third-party is forced to resort to an `unsafe` transmutation to construct `NonEmptySlice`; e.g.: 1253 | 1254 | ```rust 1255 | pub evil_constructor(src: T) -> NonEmptySlice<'static, u8> 1256 | where 1257 | T: TransmuteInto, NeglectStability>, 1258 | { 1259 | // unsafe because we `NeglectStability` 1260 | unsafe { src.unsafe_transmute_into() } 1261 | } 1262 | ``` 1263 | 1264 | Demoting `NeglectStability` to unsafe-status does not stop type authors from opting-in to stable (and thus safe) transmutations; e.g., with `derive(PromiseTransmutableFrom)`: 1265 | ```rust 1266 | pub mod crate_a { 1267 | 1268 | #[derive(PromiseTransmutableFrom)] 1269 | #[repr(C)] 1270 | pub struct NonEmptySlice<'a, T>(pub private::NonEmptySliceInner<'a, T>); 1271 | 1272 | impl<'a, T> NonEmptySlice<'a, T> { 1273 | pub fn from_array(arr: &'a [T; N], len: usize) -> Self { 1274 | assert!(len <= N && len > 0); 1275 | Self( 1276 | private::NonEmptySliceInner { 1277 | data: arr as *const T, 1278 | len, 1279 | lifetime: core::marker::PhantomData, 1280 | } 1281 | ) 1282 | } 1283 | 1284 | pub fn first(&self) -> &'a T { 1285 | unsafe { &*self.0.data } 1286 | } 1287 | } 1288 | 1289 | // introduce a private module to avoid `private_in_public` error (E0446): 1290 | pub(crate) mod private { 1291 | #[derive(PromiseTransmutableFrom)] 1292 | #[repr(C)] 1293 | pub struct NonEmptySliceInner<'a, T> { 1294 | pub data: *const T, 1295 | pub len: usize, 1296 | pub lifetime: core::marker::PhantomData<&'a ()>, 1297 | } 1298 | } 1299 | 1300 | } 1301 | ``` 1302 | In the above example, the type author declares `NonEmptySlice` and `NonEmptySliceInner` to be stably instantiatable via transmutation. Given this, a third-party no longer needs to resort to `unsafe` code to violate the the invariants on `inner`: 1303 | ```rust 1304 | pub evil_constructor(src: T) -> NonEmptySlice<'static, u8> 1305 | where 1306 | T: TransmuteInto>, 1307 | { 1308 | src.transmute_into() 1309 | } 1310 | 1311 | evil_constructor(0u128).first() // muahaha! 1312 | ``` 1313 | This safety hazard is not materially different from the one that would be induced if the type author implemented `DerefMut` for `NonEmptySlice`, or made the `private` module `pub`, or otherwise explicitly provided outsiders with unrestricted mutable access to `data`. 1314 | 1315 | ##### Recommendation 1316 | We recommend that that implementers of this RFC initially simplify constructability by: 1317 | - adopting our simplified definition of constructability 1318 | - demoting `NeglectStability` to unsafe status (i.e., not implementing `SafeTransmuteOptions` for `NeglectStability`; *only* `TransmuteOptions`) 1319 | - advise users that implementing the stability declaration traits on types that are not fully-implicitly constructable will be a compiler-error will be a compiler error (i.e., these traits must not be implemented on types exploiting the pub-in-priv trick) 1320 | 1321 | If and when the implementation of `TransmuteFrom` encodes our complete definition of constructability, `NeglectStability` shall become a safe transmute option. 1322 | 1323 | 1324 | # Drawbacks 1325 | [drawbacks]: #drawbacks 1326 | 1327 | ## No Notion of Platform Stability 1328 | The stability declaration traits communicate library layout stability, but not *platform* layout stability. A transmutation is platform-stable if it compiling one one platform implies it will compile on all other platforms. Unfortunately, platform-unstable types are common; e.g.: 1329 | 1330 | - All primitive number types have platform-dependent [endianness](https://en.wikipedia.org/wiki/Endianness). 1331 | - All pointer-related primitive types (`usize`, `isize`, `*const T`, `*mut T`, `&T`, `&mut T`) possess platform-dependent layouts; their sizes and alignments are well-defined, but vary between platforms. Concretely, whether `usize` is `TransmuteInto<[u8; 4]>` or `TransmuteInto<[u8; 8]>` will depend on the platform. 1332 | - The very existence of some types depends on platform, too; e.g., the contents of [`core::arch`](https://doc.rust-lang.org/stable/core/arch/), [`std::os`](https://doc.rust-lang.org/stable/std/os/), and [`core::sync::atomic`](https://doc.rust-lang.org/stable/std/sync/atomic/) all depend on platform. 1333 | 1334 | Our proposed stability system is oblivious to the inter-platform variations of these types. Expanding our stability system to be aware of inter-platform variations would introduce considerable additional complexity: 1335 |
    1336 |
  1. 1337 | 1338 | **Cognitive Complexity:** For types whose layout varies between platforms, the [stability] declaration traits could, *perhaps*, be adapted to encode platform-related guarantees. We anticipate this would contribute substantial cognitive complexity. Type authors, even those with no interest in cross-platform stability, would nonetheless need to reason about the layout properties of their types on platforms that might not yet exist. 1339 |
  2. 1340 |
  3. 1341 | 1342 | **Ergonomic Complexity:** Platform instabilities are contagious: a type that *contains* a platform-unstable type is, itself, platform-unstable. Due to the sheer virulence of types with platform-dependent layouts, an explicit '`NeglectPlatformStability`' option would need to be used for *many* simple transmutations. The ergonomic cost of this would also be substantial. 1343 | 1344 |
  4. 1345 |
  5. 1346 | 1347 | **Implementation Complexity:** The mechanisms proposed by this RFC are, fundamentally, applications of and additions to Rust's type system (i.e., they're traits). Mechanisms that impact platform stability, namely `#[cfg(...)]` annotations, long precede type-resolution and layout computation in the compilation process. For instance, it's possible to define types with impossible layouts: 1348 | ```rust 1349 | #[cfg(any())] 1350 | struct Recursive(Recursive); 1351 | ``` 1352 | This program compiles successfully on all platforms because, from the perspective of later compilation stages, `Recursive` may as well not exist. 1353 | 1354 |
  6. 1355 |
1356 | 1357 | The issues of platform layout stability exposed by this RFC are not fundamentally different from the challenges of platform API stability. These challenges are already competently addressed by the mechanisms proposed in [RFC1868](https://github.com/rust-lang/rfcs/pull/1868). For this reason, and for the aforementioned concerns of additional complexity, we argue that communicating and enforcing platform layout stability must remain outside the scope of this RFC. 1358 | 1359 | ## Stability of *Unsafe* Transmutations 1360 | [drawback-unsafe-stability]: #Stability-of-Unsafe-Transmutations 1361 | 1362 | The model of stability proposed by this RFC frames stability as a quality of *safe* transmutations. A type author cannot specify stability archetypes for *unsafe* transmutations, and it is reasonable to want to do so. 1363 | 1364 | To accommodate this, we may modify the definitions of `PromiseTransmutableFrom` and `PromiseTransmutableInto` to consume an optional `Neglect` parameter, to allow for stability declarations for unsafe transmutations: 1365 | ```rust 1366 | pub trait PromiseTransmutableFrom 1367 | where 1368 | Neglect: TransmuteOptions 1369 | { 1370 | type Archetype 1371 | : TransmuteInto> 1372 | + PromiseTransmutableInto>; 1373 | } 1374 | 1375 | pub trait PromiseTransmutableInto 1376 | where 1377 | Neglect: TransmuteOptions 1378 | { 1379 | type Archetype 1380 | : TransmuteFrom> 1381 | + PromiseTransmutableInto>; 1382 | } 1383 | ``` 1384 | Implementations of these traits for a given `Neglect` declares that a transmutation which is accepted while neglecting a particular set of checks (namely the set encoded by `Neglect`) will *continue* to be possible. 1385 | 1386 | We omit these definition from this RFC's recommendations because they are not completely satisfying. For instance, `Neglect` is a *logically* unordered set of options, but is encoded as a tuple (which *is* ordered). To declare a transmutation that requires neglecting validity and alignment checks as stable, only *one* of these impls ought to be necessary: 1387 | 1388 | ```rust 1389 | impl PromiseTransmutableFrom<(NeglectAlignment, NeglectValidity)> for Foo 1390 | { 1391 | ... 1392 | } 1393 | 1394 | impl PromiseTransmutableFrom<(NeglectValidity, NeglectAlignment)> for Foo 1395 | { 1396 | ... 1397 | } 1398 | ``` 1399 | Writing *both* impls (as we do above) is logically nonsense, but is nonetheless supported by Rust's coherence rules. 1400 | 1401 | 1402 | # Rationale and alternatives 1403 | [rationale-and-alternatives]: #rationale-and-alternatives 1404 | 1405 | 1406 | ## Rationale: `TransmuteFrom`/`TransmuteInto` 1407 | 1408 | ### Why support arbitrary transmutation? 1409 | Some [prior art][prior-art], especially in the crate ecosystem, provides an API that [only supports transmutations involving particular types](#Source-and-Destination-Types-Supported) (e.g., from/into bytes). As we discuss in the [prior art][prior-art] section, we believe that the inflexibility of such approaches make them a poor basis of a language proposal. In particular, these restrictive approaches don't leave room to grow: supporting additional transmutations requires additional traits. 1410 | 1411 | The API advocated by this proposal is unopinionated about what transmutations users might wish to do, and what transmutations the compiler is able to reason about. The implementation of this RFC may be initially very simple (and perhaps support no more than the restrictive approaches allow for), but then subsequently grow in sophistication—*without* necessitating public API changes. 1412 | 1413 | ### Why *two* traits? 1414 | If `TransmuteInto` is implemented in terms of `TransmuteFrom`, why provide it at all? We do so for consistency with libcore's [`From`/`Into`](https://doc.rust-lang.org/stable/rust-by-example/conversion/from_into.html) traits, and because directionality conveys intent: `TransmuteFrom` connotes *conversion*, whereas `TransmuteInto` connotes initialization. We believe that the supporting code examples of this RFC demonstrate the explanatory benefits of providing *both* traits. 1415 | 1416 | ## Rationale: Transmutation Options 1417 | 1418 | ### Granularity 1419 | Although the focus of our API is statically-correct, infalible transmutations, the ability to opt-out of particular static checks is essential for building safer *fallible* mechanisms, such as alignment-fallible [reference casting][ext-ref-casting], or validity-fallible transmutations (e.g., `bool` to `u8`). 1420 | 1421 | ### Representation 1422 | Although transmutations options exist at a type-level, they're represented as type-level tuples, whose familiar syntax is identical to value-level tuples. An empty tuple seems like the natural choice for encoding *don't neglect anything*. 1423 | 1424 | We could not identify any advantages to representing options with const-generics. There is no clear syntactic advantage: tuples remain the most natural way to encode ad-hoc products of items. The comparative lack of default values for const-generic parameters poses an ergonomic *disadvantage*. 1425 | 1426 | 1427 | ## Rationale: Stability 1428 | 1429 | ### Why do we need a stability system? 1430 | 1431 | At least two requirements necessitate the presence of a stability system: 1432 | 1433 | #### Mitigating a Unique Stability Hazard 1434 | The usual rules of SemVer stability dictate that if a trait is is implemented in a version `m.a.b`, it will *continue* to be implemented for all versions `m.x.y`, where `x ≥ a` and `y ≥ b`. **`TransmuteFrom` is the exception to this rule**. It would be irresponsible to do nothing to mitigate this stability hazard. 1435 | 1436 | The compromise made by this RFC is that **`TransmuteFrom` should be stable-by-default**: 1437 | - `Dst: TransmuteFrom` follows the usual SemVer rules, 1438 | - `Dst: TransmuteFrom` *does not*. 1439 | 1440 | #### Mitigating a Possible Safety Hazard 1441 | The [simplified formulation of constructability](#simplifying-constructability) provides an initially-simpler implementation path at the cost of a soundness hole. There are three possible mitigations: 1442 | - *Pretend it does not exist.* Intentional soundness holes would not bode well for this RFC's acceptance. 1443 | - *Only provide unsafe transmutation; not safe transmutation.* This option fails to remove any `unsafe` blocks from end-users' code. 1444 | - *Allow safe transmutations only when the type authors have promised they will not create a situation that would compromise safety.* **We recommend this option.** 1445 | 1446 | This promise is inherently one of stability—the type author is vowing that they will not change the implementation of their type in a way that violates the no-pub-in-priv safety invariant of safe transmutation. 1447 | 1448 | 1449 | ### Why this *particular* stability system? 1450 | The proposed stability system is both simple, flexible, and extensible. Whereas ensuring the soundness and safety of `TransmuteFrom` requires non-trivial compiler support, stability does not—it is realized as merely two normal traits and an `impl`. 1451 | 1452 | This formulation is flexible: by writing custom `Archetype`s, the [stability declaration traits][stability] make possible granular and incomplete promises of layout stability (e.g., guaranteeing the size and validity qualities of a type, but *not* its alignment. Members of the safe-transmute working group have [expressed](https://rust-lang.zulipchat.com/#narrow/stream/216762-project-safe-transmute/topic/Transmutability.20Intrinsic/near/202712834) an interest in granular stability declarations. 1453 | 1454 | Finally, this formulation is extensible. The range of advance use-cases permitted by these traits is constrained only by the set of possible `Archetype`s, which, in turn, is constrained by the completeness of `TransmuteFrom`. As the implementation of `TransmuteFrom` becomes more complete, so too will the range of advance use-cases accommodated by these traits. 1455 | 1456 | 1457 | ### Couldn't `#[repr(C)]` denote stability? 1458 | In our proposal, `#[repr(C)]` does not connote any promises of transmutation stability for SemVer purposes. It has [been suggested](https://rust-lang.zulipchat.com/#narrow/stream/216762-project-safe-transmute/topic/RFC.3A.20Stability.20Declaration.20Traits/near/204011238) that the presence of `#[repr(C)]` *already* connotes total transmutation stability; i.e., that the type's author promises that the type's size and alignment and bit-validity will remain static. If this is true, then an additional stability mechanism is perhaps superfluous. However, we are unaware of any authoritative documentation indicating that `#[repr(C)]` carries this implication. Treating `#[repr(C)]` as an indicator of transmutation stability [would](https://rust-lang.zulipchat.com/#narrow/stream/216762-project-safe-transmute/topic/typic/near/201165897) thus pose a stability hazard. 1459 | 1460 | 1461 | ## Alternative: Implementing this RFC in a Crate 1462 | 1463 | This RFC builds on ample [prior art][prior-art] in the crate ecosystem, but these efforts strain against the fundamental limitations of crates. Fundamentally, safe transmutation efforts use traits to expose layout information to the type system. The burden of ensuring safety [is usually either placed entirely on the end-user, or assumed by complex, incomplete proc-macro `derives`][mechanism-manual]. 1464 | 1465 | An exception to this rule is the [typic][crate-typic] crate, which utilizes complex, type-level programming to emulate a compiler-supported, "smart" `TransmuteFrom` trait (like the one proposed in this RFC). Nonetheless, [typic][crate-typic] is fundamentally limited: since Rust does not provide a type-level mechanism for reflecting over the structure of arbitrary types, even [typic][crate-typic] cannot judge the safety of a transmutation without special user-added annotations on type definitions. Although [typic][crate-typic] succeeds as a proof-of-concept, its maintainability is questionable, and the error messages it produces are [lovecraftian](https://en.wikipedia.org/wiki/Lovecraftian_horror). 1466 | 1467 | The development approaches like [typic][crate-typic]'s could, perhaps, be eased by stabilizing [frunk](https://crates.io/crates/frunk)-like structural reflection, or (better yet) by stabilizing a compiler plugin API for registering "smart" traits like `TransmuteFrom`. However, we suspect that such features would be drastically harder to design and stabilize. 1468 | 1469 | Regardless of approach, almost all [prior art][prior-art] attempts to reproduce knowledge *already* possessed by `rustc` during the compilation process (i.e., the layout qualities of a concrete type). Emulating the process of layout computation to any degree is an error-prone duplication of effort between `rustc` and the crate, in a domain where correctness is crucial. 1470 | 1471 | Finally, community-led, crate-based approaches are, inescapably, unauthoritative. These approaches are incapable of fulfilling our motivating goal of providing a *standard* mechanism for programmers to statically ensure that a transmutation is safe, sound, or stable. 1472 | 1473 | # Prior art 1474 | [prior-art]: #prior-art 1475 | 1476 | [crate-plain]: https://crates.io/crates/plain 1477 | [crate-bytemuck]: https://crates.io/crates/bytemuck 1478 | [crate-dataview]: https://crates.io/crates/dataview 1479 | [crate-safe-transmute]: https://crates.io/crates/safe-transmute 1480 | [crate-pod]: https://crates.io/crates/pod 1481 | [crate-uncon]: https://crates.io/crates/uncon 1482 | [crate-typic]: https://crates.io/crates/typic 1483 | [crate-zerocopy]: https://crates.io/crates/zerocopy 1484 | [crate-convute]: https://crates.io/crates/convute 1485 | [crate-byterepr]: https://crates.io/crates/byterepr 1486 | 1487 | [2017-02]: https://internals.rust-lang.org/t/pre-rfc-safe-coercions/4823 1488 | [2018-03]: https://internals.rust-lang.org/t/pre-rfc-frombits-intobits/7071 1489 | [2018-03-18]: https://internals.rust-lang.org/t/pre-rfc-frombits-intobits/7071/23 1490 | [2018-05-18]: https://internals.rust-lang.org/t/pre-rfc-trait-for-deserializing-untrusted-input/7519 1491 | [2018-05-23]: https://github.com/joshlf/rfcs/blob/joshlf/from-bytes/text/0000-from-bytes.md 1492 | [2019-09]: https://internals.rust-lang.org/t/specifying-a-set-of-transmutes-from-struct-t-to-struct-u-which-are-not-ub/10917 1493 | [2019-11]: https://internals.rust-lang.org/t/pre-rfc-safe-transmute/11347 1494 | [2019-12-05-gnzlbg]: https://gist.github.com/gnzlbg/4ee5a49cc3053d8d20fddb04bc546000 1495 | [2019-12-05-v2]: https://internals.rust-lang.org/t/pre-rfc-v2-safe-transmute/11431 1496 | [2020-07]: https://internals.rust-lang.org/t/pre-rfc-explicit-opt-in-oibit-for-truly-pod-data-and-safe-transmutes/2361 1497 | 1498 | ## Prior Art: Rust 1499 | [prior-art-rust]: #prior-art-rust 1500 | 1501 | A handful of dimensions of variation characterize the distinctions between prior art in Rust: 1502 | - conversion complexity 1503 | - conversion fallibility 1504 | - source and destination types supported 1505 | - implementation mechanism 1506 | - stability hazards 1507 | 1508 | We review each of these dimensions in turn, along with this proposal's location along these dimensions: 1509 | 1510 | ### Conversion Complexity 1511 | Prior work differs in whether it supports complex conversions, or only simple transmutation. [*Pre-RFC FromBits/IntoBits*][2018-03]'s proposed traits include conversion methods that are implemented by type authors. Because end-users provide their own definitions of these methods, they can be defined to do more than just transmutation (e.g., slice casting). (This approach is similar to the [uncon][crate-uncon] crate's [`FromUnchecked`](https://docs.rs/uncon/1.*/uncon/trait.FromUnchecked.html) and [`IntoUnchecked`](https://docs.rs/uncon/1.*/uncon/trait.IntoUnchecked.html) traits, which provide unsafe conversions between types. These traits are safe to implement, but their conversion methods are not.) 1512 | 1513 | In contrast, our RFC focuses only on transmutation. Our `TransmutableFrom` and `TransmutableInto` traits serve as both a marker *and* a mechanism: if `Dst: TransmuteFrom`, it is sound to transmute from `Dst` into `Src` using `mem::transmute`. However, these traits *also* provide transmutation methods that are guaranteed to compile into nothing more complex than a `memcpy`. These methods cannot be overridden by end-users to implement more complex behavior. 1514 | 1515 | The signal and transmutability and mechanism are, in principle, separable. The [convute][crate-convute] crate's [`Transmute`](https://docs.rs/convute/0.2.0/convute/marker/trait.Transmute.html) trait is an unsafe marker trait representing types that can be transmuted into `T`. This is *just* a marker trait; the actual conversion mechanisms are provided by a [separate suite](https://docs.rs/convute/0.2.0/convute/convert/index.html) of traits and functions. Our RFC combines marker with mechanism because we feel that separating these aspects introduces additional complexity with little added value. 1516 | 1517 | ### Conversion Fallibility 1518 | Prior work differs in whether it supports only infallible conversions, or fallible conversions, too. The [convute][crate-convute] crate's [`TryTransmute`](https://docs.rs/convute/0.2.0/convute/marker/trait.TryTransmute.html) trait provides a method, `can_transmute`, that returns true a transmutation from `Self` to `T` is valid for a particular value of `&self`. An early version of [typic][crate-typic] abstracted a similar mechanism into an [`Invariants`](https://docs.rs/typic/0.1.0/typic/transmute/trait.Invariants.html) trait, with additional facilities for error reporting. [*Draft-RFC: `Compatible`/`TryCompatible`*][2019-12-05-gnzlbg] employs a similar mechanism to typic. 1519 | 1520 | Typic removed support for fallible transmutation after reckoning with several challenges: 1521 | - The causes of uncertain failure could be language-imposed (e.g., alignment or validity requirements), or library imposed (i.e., invariants placed on a structure's private fields). 1522 | - The points of uncertain failures could be arbitrarily 'deep' into the fields of a type. 1523 | - Error reporting incurs a runtime cost commensurate with the detail of the reporting, but the detail of reporting required by end-user depends on use-case, not just type. For instance: for some use-cases it may be necessary to know where and why a byte was not a valid `bool`; in others it may be sufficient to know simply *whether* an error occurred. 1524 | 1525 | Finally, we observed that the mechanisms of fallible transmutation were basically separable from the mechanisms of infallible transmutation, and thus these challenges could be addressed at a later date. For these reasons, our RFC *only* addresses infallible transmutation. 1526 | 1527 | While this RFC does not provide a grand, all-encompassing mechanism for fallible transmutation, the fundamental mechanisms of our RFC are useful for constructing safer, purpose-built fallible conversion mechanisms; e.g.: 1528 | ```rust 1529 | /// Try to convert a `&T` into `&U`. 1530 | /// 1531 | /// This produces `None` if the referent isn't appropriately 1532 | /// aligned, as required by the destination type. 1533 | pub fn try_cast_ref<'t, 'u, T, U>(src: &'t T) -> Option<&'u U> 1534 | where 1535 | &'t T: TransmuteInto<&'u U, NeglectAlignment>, 1536 | { 1537 | if (src as *const T as usize) % align_of::() != 0 { 1538 | None 1539 | } else { 1540 | // Safe because we dynamically enforce the alignment 1541 | // requirement, whose static check we chose to neglect. 1542 | Some(unsafe { src.unsafe_transmute_into() }) 1543 | } 1544 | } 1545 | ``` 1546 | In this approach, our RFC is joined by crates such as [plain](https://docs.rs/plain/0.2.3/plain/#functions), [bytemuck](https://docs.rs/bytemuck/1.*/bytemuck/#functions), [dataview](https://docs.rs/dataview/0.1.1/dataview/struct.DataView.html#methods), [safe-transmute](https://docs.rs/safe-transmute/0.11.0/safe_transmute/fn.transmute_one.html), [zerocopy](https://docs.rs/zerocopy/0.3.0/zerocopy/struct.LayoutVerified.html#methods), and [byterepr](https://docs.rs/byterepr/0.1.0/byterepr/trait.ByteRepr.html#provided-methods), and several pre-RFCs (such as [this][2018-05-18] and [this](https://github.com/joshlf/rfcs/blob/joshlf/from-bits/text/0000-from-bits.md#library-functions)). The ubiquity of these mechanisms makes a strong case for their inclusion in libcore. 1547 | 1548 | ### Source and Destination Types Supported 1549 | Prior work differs in whether its API surface is flexible enough to support transmutation between arbitrary types, or something less. 1550 | 1551 | #### Arbitrary Types 1552 | Approaches supporting transmutations between arbitrary types invariably define traits akin to: 1553 | ```rust 1554 | /// Indicates that `Self` may be transmuted into `Dst`. 1555 | pub unsafe trait TransmuteInto 1556 | { ... } 1557 | 1558 | /// Indicates that `Self` may be transmuted from `Dst`. 1559 | pub unsafe trait TransmuteFrom 1560 | { ... } 1561 | ``` 1562 | This approach, taken by our RFC, is used by at least two crates: 1563 | - The [convute][crate-convute] crate's [`Transmute`](https://docs.rs/convute/0.2.0/convute/marker/trait.Transmute.html) trait is akin to the above definition of `TransmuteInto`. 1564 | - The [typic][crate-typic] crate's [`TransmuteInto`](https://docs.rs/typic/0.3.0/typic/transmute/trait.TransmuteInto.html) and [`TransmuteFrom`](https://docs.rs/typic/0.3.0/typic/transmute/trait.TransmuteFrom.html) traits almost exactly mirror the above definitions. 1565 | 1566 | ...and several proposals: 1567 | - [*Pre-RFC: Safe coercions*][2017-02] proposes a `Coercible` trait that is implemented if `A` is safely transmutable into `B`. 1568 | - [*Pre-RFC: `FromBits`/`IntoBits`*][2018-03] proposes the traits `IntoBits` and `FromBits.` 1569 | - [*Draft-RFC: `FromBytes`*][2018-05-23] proposes the traits `IntoBytes` and `FromBytes.` 1570 | - [*Draft-RFC: `Compatible`/`TryCompatible`*][2019-12-05-gnzlbg] proposes the trait `Compatible`, akin to the above definition of `TransmuteInto`. 1571 | 1572 | ##### From/Into Bytes Transmutations 1573 | Other approaches adopt an API that only supports transmutation of a type into initialized bytes, and from initialized bytes. These approaches invariably define traits akin to: 1574 | ```rust 1575 | /// Indicates that a type may be transmuted into an appropriately-sized array of bytes. 1576 | pub unsafe trait IntoBytes 1577 | {} 1578 | 1579 | /// Indicates that a type may be transmuted from an appropriately-sized array of bytes. 1580 | pub unsafe trait FromBytes 1581 | {} 1582 | ``` 1583 | This is the approach taken by the [zerocopy][crate-zerocopy] crate, and the [*Pre-RFC: Safe Transmute*][2019-11] and [*Pre-RFC: Safe Transmute v2*][2019-12-05-v2] proposals. 1584 | 1585 | This approach is strictly less flexible than an API supporting transmutation between arbitrary types. It is incapable of representing transmutations of bytes into types with validity constraints, and incapable of representing transmutations of types with padding bytes into bytes. 1586 | 1587 | Supporting additional transmutation source and destination types requires a commensurate addition of conversion traits. For instance, some of [zerocopy][crate-zerocopy]'s users [require](https://fuchsia-review.googlesource.com/c/fuchsia/+/306036/2#message-a1a0c9cf16e3dec24e7b0548e3c09382f63783f0) a trait that reflects types which can be transmuted from a buffer of zeroed bytes. This would require introducing an additional trait, `FromZeros`. 1588 | 1589 | An advantage of this API is that it gives descriptive names to perhaps the two most common transmutations. However, an API providing transmutation between arbitrary types can encode `FromBytes` and `IntoBytes`: 1590 | ```rust 1591 | // `Dst` is `FromBytes` if it can be safely transmuted *from* an 1592 | // equivalently sized array of `u8`. 1593 | unsafe impl FromBytes for Dst 1594 | where 1595 | Dst: TransmuteFrom<[u8; size_of::()]>, 1596 | {} 1597 | 1598 | // `Src` is `IntoBytes` if it can be safely transmuted *into* an 1599 | // equivalently sized array of `u8`. 1600 | unsafe impl IntoBytes for Src 1601 | where 1602 | Src: TransmuteInto<[u8; size_of::()]>, 1603 | {} 1604 | ``` 1605 | For these reasons, we argue that a `FromBytes`/`ToBytes` style API is a poor foundation for in-language safe transmutation. 1606 | 1607 | ##### Bytes-to-Bytes Transmutations (aka "Plain Old Data") 1608 | Finally, many approaches (especially crates) supply a marker trait that represents "plain old data"; e.g.: 1609 | ```rust 1610 | /// Implemented by types that are "plain old data": 1611 | pub unsafe trait PlainOldData 1612 | {} 1613 | ``` 1614 | This sort of trait is present in crates such as [plain](https://docs.rs/plain/0.2.3/plain/trait.Plain.html), [bytemuck](https://docs.rs/bytemuck/1.*/bytemuck/trait.Pod.html), [dataview](https://docs.rs/dataview/0.1.1/dataview/trait.Pod.html), [safe-transmute](https://docs.rs/safe-transmute/0.11.0/safe_transmute/trivial/trait.TriviallyTransmutable.html), and [pod](https://docs.rs/pod/0.5.0/pod/trait.Pod.html), and at least two language proposals ([here][2018-05-18] and [here][2020-07]). 1615 | 1616 | The exact definition of what constitutes "plain old data" varies between crates. One simple definition is that a type `T` is "plain old data" if it can be transmuted both from and into initialized bytes; i.e.: 1617 | ```rust 1618 | unsafe impl PlainOldData for T 1619 | where 1620 | T: FromBytes + IntoBytes, 1621 | {} 1622 | ``` 1623 | 1624 | This definition precludes useful transmutations. For instance, `MaybeUninit` is transmutable from a `u8`, but not *into* a `u8`. 1625 | 1626 | Given this inflexibility, we argue that this approach is a poor foundation for in-language safe transmutation. 1627 | 1628 | 1629 | ### Implementation Mechanism 1630 | Not only does prior work differ in which traits are used to encode valid transmutations, they differ in the level of user intervention required to take advantage of the traits. 1631 | 1632 | #### Manual 1633 | [mechanism-manual]: #Manual 1634 | Fully manual approaches require type authors to implement the transmutation traits manually. The involved traits are `unsafe`, so it is up to type authors to verify for themselves that their hand-written implementations are sound. This is the approach taken by crates such as [plain][crate-plain], [bytemuck][crate-bytemuck], [safe-transmute][crate-safe-transmute], and [pod][crate-pod], and at least one language proposal: [*Pre-RFC: Safe Transmute*][2019-12-05-v2] (which advocates for a "plain old data" API). 1635 | 1636 | In semi-manual approaches, type authors simply `derive` the applicable traits, using `derive` macros that produce a compile-error if the implementation is not sound. This approach is realized by crates such as ([zerocopy](https://docs.rs/zerocopy/0.3.0/zerocopy/#derives), [zeroable](https://docs.rs/zeroable/0.2.0/zeroable/) and [dataview](https://docs.rs/dataview/0.1.1/dataview/derive.Pod.html)) and advocated by at least two language proposals: [*Pre-RFC: Safe Transmute v2*][2019-12-05-v2] (which advocates for a `FromBytes`/`IntoBytes`-style API), and [*Pre-RFC FromBits/IntoBits*][2018-03] (which advocates for a general-transmutation API). 1637 | 1638 | We believe that the implementation burden these approaches place on end-users, and their inflexibility, make them a poor foundation for in-language safe transmutation: 1639 | - These approaches require authors to implement and, potentially, verify a large number of `unsafe` traits, ranging from *O(n)* implementations for plain-old-data trait approaches, to potentially [*many* more](https://internals.rust-lang.org/t/pre-rfc-frombits-intobits/7071/28). 1640 | - These approaches are generally impractical for APIs that permit truly general transmutation, as type authors can only construct implementations of the transmutation traits for types they have at their disposal. 1641 | - These approaches conflate transmutation stability with transmutation safety. An end-user wishing to transmute a type for which its author has *not* manually implemented the applicable traits must resort to the wildly unsafe `mem::transmute`. 1642 | 1643 | 1644 | #### Automatic 1645 | Automatic approaches implement the transmutation traits without user intervention, whenever it is sound to do so. This is the approach taken by our RFC. Automatic mechanisms appear in at least four prior language proposals: 1646 | - [*Pre-RFC: Safe coercions*][2017-02] 1647 | - [*Draft-RFC: `from_bytes`*][2018-05-23] 1648 | - [*Pre-RFC: Trait for deserializing untrusted input*][2018-05-18] 1649 | - [*Draft-RFC: `compatible_trait`*][2019-12-05-gnzlbg] 1650 | 1651 | The [typic][crate-typic] crate mocks a fully-automatic approach: its `TransmuteFrom` trait is usable with any types that are `repr(C)`, or otherwise have a well-defined memory layout. (In practice, since Rust lacks reflection over type definitions, `repr(C)` annotations much be changed to `typic::repr(C)`.) 1652 | 1653 | ### Stability Hazards 1654 | Fully automatic approaches introduce, at the very least, a stability hazard: they supply a safe constructor for types, without the consent of those types' authors. If a type author hid the internals of their type because they do not wish for its implementation details to become a part of the type's API for SemVer purposes, an automatic transmutation mechanism subverts that intent. 1655 | 1656 | No attempt to avoid this hazard is made by most of the proposals featuring automatic mechanisms; e.g.: 1657 | - [*Draft-RFC: `from_bytes`*][2018-05-23] 1658 | - [*Pre-RFC: Trait for deserializing untrusted input*][2018-05-18] 1659 | - [*Draft-RFC: `compatible_trait`*][2019-12-05-gnzlbg] 1660 | 1661 | #### Hazard-Avoidant 1662 | The automatic mechanism proposed by [*Pre-RFC: Safe coercions*][2017-02] exploits field visibility, requiring that all fields that have different types in `Src` and `Dst` are visible at the location where the coercion is made. This approach falls short in three respects: 1663 | 1. Confining the visibility requirement only to fields of *different* types is insufficient; two different types with identical field types may subject those fields to different invariants. 1664 | 2. The 'location' where the coercion is made is ill-defined; the presence of the proposed `Coercible` trait may be far-removed from the location of the actual conversion (if any conversion occurs at all). 1665 | 3. Field visibility stabilizes the structure of a type, but *not* its layout (e.e., its size). 1666 | 1667 | Our RFC exploits the related concept of *constructability*, which is a property of a struct, or enum variant (rather than solely a property of fields). However, we recognize that it may be difficult to test for constructability within the trait resolution process. 1668 | 1669 | The simplified definition of *constructability* we propose is the same employed by [typic][crate-typic] (which uses the term "visibility"). [Typic][crate-typic] regards the pub-in-priv soundness hole of the simplified definition to be sufficiently niche that `NeglectStability` remains "safe". However, unlike [typic][crate-typic], we believe that this simplified definition imposes a safety hazard substantial enough to warrant making `NeglectStability` initially usable with *only* unsafe transmutes. 1670 | 1671 | Our RFC separates *constructability*, which concerns what aspects of a type's structure are part of its public API, and *stability*, which concerns the aspects of a type's layout that are part of its public API for SemVer purposes. This distinction does not appear in prior work. 1672 | 1673 | 1674 | ## Prior Art: Haskell 1675 | 1676 | Haskell's [`Coercible`](https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Coerce.html#t:Coercible) typeclass is implemented for all types `A` and `B` when the compiler can infer that they have the same representation. As with our proposal's `TransmuteFrom` trait, instances of this typeclass are created "on-the-fly" by the compiler. `Coercible` primarily provides a safe means to convert to-and-from newtypes, and does not seek to answer, for instance, if two `u8`s are interchangeable with a `u16`. 1677 | 1678 | Haskell takes an algebraic approach to this problem, reasoning at the level of type definitions, not type layouts. However, not all type parameters have an impact on1 a type's layout; for instance: 1679 | ```rust 1680 | #[repr(C)] 1681 | struct Bar(PhantomData); 1682 | 1683 | #[repr(transparent)] 1684 | struct Foo(T, Bar); 1685 | ``` 1686 | `Foo`'s layout is impacted solely by `T`, not `U`, but this isn't necessarily clear by looking at the definition of `Foo`. To reason about these scenarios, Haskell introduces the concept of type parameter [*roles*](https://gitlab.haskell.org/ghc/ghc/-/wikis/roles)—labels that denote the relationship of a type parameter to coercibility. 1687 | 1688 | Our RFC does not need the concept of roles, because it does not attempt to abstractly reason about type definitions. Rather, it reasons about type *layouts*. This example, for instance, does not pose a challenge to our proposal: 1689 | ```rust 1690 | trait SomeTrait { type AssociatedType; } 1691 | 1692 | #[repr(C)] 1693 | struct MyStruct(pub T, pub T::AssociatedType); 1694 | ``` 1695 | For a *particular* `T`, `MyStruct` will have a *particular* layout. Our proposed `TransmuteFrom` trait reasons about the 1696 | *layouts* of types (which are fully concrete), not the *definitions* (which may be somewhat abstract). 1697 | 1698 | 1699 | # Unresolved questions 1700 | [unresolved-questions]: #unresolved-questions 1701 | 1702 | ### Questions To Be Resolved Before RFC Acceptance 1703 | The following unresolved questions should be resolved during the RFC process: 1704 | 1705 | ##### Unhandled Use-Cases? 1706 | We endeavored to design an API surface with ([nearly][drawbacks]) zero compromises. However, if you have a use-case that you believe is neither satisfied outright by our proposal, nor [aided][future-possibilities] by our proposal, we would *urgently* like to hear of it. 1707 | 1708 | ##### Extensions for Inclusion? 1709 | In [*Future Possibilities*][future-possibilities], we propose a number of additional abstractions that are aided by this RFC. Some of these abstractions are commonplace in [prior art][prior-art] and should perhaps be included with this RFC. Some of our proposed extensions could begin their crates that work on stable Rust; others, such as [generic atomics][future-possibility-generic-atomics], require nightly-only intrinsics. 1710 | 1711 | ### Questions To Be Resolved Before Feature Stabilization 1712 | The following unresolved questions should be resolved before feature stabilization: 1713 | 1714 | ##### Layout-Stability for Unsafe Transmutations? 1715 | We [observe][drawback-unsafe-stability] that our proposed model for stability declaration, although very expressive, does not permit type authors to declare the stability of *unsafe* transmutations. Alongside that observation, we suggest a [SemVer-compatible](https://github.com/rust-lang/rfcs/blob/master/text/1105-api-evolution.md#minor-change-adding-a-defaulted-type-parameter) upgrade of the stability declaration traits that may resolve this shortcoming. 1716 | 1717 | While it is unclear if there is any demand for this degree of flexibility, this upgrade-path should be carefully considered *before* stabilizing (and thus committing) to this RFC's layout stability declaration traits. 1718 | 1719 | 1720 | ### Questions Out of Scope 1721 | We consider the following unresolved questions to be out-of-scope of *this* RFC process: 1722 | 1723 | ##### Design of `NeglectConstructability`? 1724 | `TransmuteFrom` and `TransmuteInto` require that the destination type has a matching constructor in which all fields are marked `pub`. Conspicuously *missing* from this RFC is a `NeglectConstructability` unsafe option to disable this check. 1725 | 1726 | The omission is intentional. The consequences of such an option are suprising in both their subtlety and their unsafety. Some of unsafe Rust's hairiest interactions lie at the intersections of `!Send`, `!Sync`, `UnsafeCell` and restricted field visibility. These building blocks are used to build safe, public abstractions that encapsulate unsafe, hidden internals. 1727 | 1728 | # Future possibilities 1729 | [future-possibilities]: #future-possibilities 1730 | 1731 | ## Extension: `PromiseTransmutable` Shorthand 1732 | [extension-promisetransmutable-shorthand]: #extension-promisetransmutable-shorthand 1733 | 1734 | See [here](0000-ext-promise-transmutable.md). 1735 | 1736 | ## Extension: Layout Property Traits 1737 | 1738 | See [here](0000-ext-layout-traits.md). 1739 | 1740 | ## Extension: Byte Transmutation Traits and Safe Initialization 1741 | [extension-zerocopy]: #extension-byte-transmutation-traits-and-safe-initialization 1742 | 1743 | See [here](0000-ext-byte-transmutation.md). 1744 | 1745 | 1746 | ## Extension: Slice and `Vec` Casting 1747 | [ext-slice-casting]: #extension-slice-and-vec-casting 1748 | [ext-vec-casting]: #extension-slice-and-vec-casting 1749 | 1750 | See [here](0000-ext-container-casting.md). 1751 | 1752 | 1753 | ## Extension: `include_data!` 1754 | [future-possibility-include_data]: #Extension-include_data 1755 | 1756 | See [here](0000-ext-include-data.md). 1757 | 1758 | 1759 | ## Extension: Generic Atomics 1760 | [future-possibility-generic-atomics]: #extension-generic-atomics 1761 | 1762 | See [here](0000-ext-generic-atomic.md). 1763 | -------------------------------------------------------------------------------- /rfcs/announcement-and-charter.md: -------------------------------------------------------------------------------- 1 | - Feature Name: `project-safe-transmute` 2 | - Start Date: 2019-12-06 3 | - RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) 4 | - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) 5 | 6 | # Summary 7 | [summary]: #summary 8 | 9 | To form a project group with the purpose of designing subsequent RFCs around the 10 | topic of safe transmute between types. 11 | * This RFC explicitly builds off of processes introduced in the [FFI unwinding project 12 | group RFC](https://github.com/rust-lang/rfcs/pull/2797/files) 13 | * The primary goal of the group is to determine how to replace most uses of 14 | [`std::mem::transmute`][transmute] with safe alternatives. 15 | * Subsequent goals may include extending other language features that are made possible 16 | with safe transmute including safe reading of union fields 17 | 18 | # Motivation 19 | [motivation]: #motivation 20 | 21 | Transmuting one type to another type and vice versa in Rust is extremely dangerous --- 22 | so much so that the docs for [std::mem::transmute][transmute] are essentially a long 23 | list of how to avoid doing so. However, transmuting is often times necessary especially 24 | in lower level contexts where copy of bytes is prohibitively expensive. For instance, 25 | in extremely performance-sensitive use cases, it may be necessary to transmute from 26 | bytes instead of explicitly copying bytes from a buffer into a struct. 27 | 28 | Because of this fact, [many][zerocopy] [external][safe-transmute] [crates][bytemuck] 29 | have been developed to tackle this issue, but no single crate has managed to solidify 30 | itself as a clear favorite in this space. Additionally, while it is possible to improve 31 | on unsafe transmute considerably in libraries, having such facilities in the standard 32 | library opens up the possibility of bringing safe constructs to even more currently 33 | unsafe features. 34 | 35 | For these reasons, we plan on learning from the prior art to implement a standard way of 36 | transmuting types in a safe way. 37 | 38 | ## Details of the safe transmute project group 39 | 40 | [Repository][repository] 41 | 42 | Initial shepherds: 43 | 44 | * [rylev (Ryan)](https://github.com/rylev) 45 | 46 | Lang team liaisons: 47 | 48 | * [joshtriplett (Josh)](https://github.com/joshtriplett) 49 | 50 | ### Charter 51 | [charter]: #charter 52 | 53 | The safe transmute project group has the following initial scope: 54 | 55 | * to define APIs for allowing zero copy transmute between types in a completely 56 | memory safe manner 57 | 58 | Once this scope has been reached, the team may continue working on features that are 59 | natural extensions of safe transmute like safe reading on union fields. 60 | 61 | ### Constraints and considerations 62 | 63 | In its work, the project-group should consider various constraints and 64 | considerations: 65 | 66 | * That this feature is meant for performance sensitive workloads 67 | * That safety is of the upmost importance as there is already a way to 68 | transmute using unsafe APIs 69 | 70 | ### Participation in the project group 71 | 72 | Like any Rust group, the safe transmute project group intends to operate 73 | in a public and open fashion and welcomes participation. Visit the 74 | [repository][repository] for more details. 75 | 76 | # Drawbacks 77 | [drawbacks]: #drawbacks 78 | 79 | * It is possible that the scope of this endeavor is not large enough to warrant a 80 | separate project group. 81 | * It can be argued that the design space has not been fully explored as evidenced by 82 | the many crates that address the issue without one being the clear "go to", and thus 83 | this issue should be left to libraries for further iteration. We believe that while 84 | there is no clear winner among existing crates, they are stable enough, small enough 85 | and share enough implementation characteristics to be ready for the community to 86 | rally around one design direction in the standard library. 87 | 88 | # Prior art 89 | [prior-art]: #prior-art 90 | 91 | The formation of the project group was first discussed in the [FFI unwind 92 | project group RFC][ffi unwind]. As is state in that RFC, this working group can be 93 | considered a precursor to the current ["shepherded project group" proposal][shepherd]. 94 | 95 | # Unresolved questions and Future possibilities 96 | [unresolved-questions]: #unresolved-questions 97 | 98 | Since this RFC merely formalizes the creation of the project group, it 99 | intentionally leaves all technical details within the project's scope 100 | unresolved. 101 | 102 | # Future possibilities 103 | [future-possibilities]: #future-possibilities 104 | 105 | The project group will start with a fairly [limited scope][charter], but if the 106 | initial effort to design and stabilize APIs for safe transmute between types, 107 | there is at least one other area that can be expanded upon by this group: safe reading 108 | of union fields. 109 | 110 | [transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html 111 | [ffi unwind]: https://github.com/rust-lang/rfcs/pull/2797 112 | [zerocopy]: https://docs.rs/zerocopy 113 | [safe-transmute]: https://docs.rs/safe-transmute 114 | [bytemuck]: https://docs.rs/bytemuck 115 | [sheherd]: http://smallcultfollowing.com/babysteps/blog/2019/09/11/aic-shepherds-3-0/ 116 | -------------------------------------------------------------------------------- /terminology/misc.md: -------------------------------------------------------------------------------- 1 | # Miscellaneous terminology 2 | 3 | -------------------------------------------------------------------------------- /terminology/spec-terminology.md: -------------------------------------------------------------------------------- 1 | # Terminology about specifications 2 | 3 | Language and platform specifications have several different terms used 4 | to describe how well-defined a language feature is, i.e., how well 5 | constrained the runtime behavior is. In cases where our terminology 6 | overlaps with that from other communities, we try to remain generally 7 | compatible. 8 | 9 | 10 | 11 | ## Undefined Behavior 12 | 13 | As is typical within the Rust community we use the phrase **undefined 14 | behavior** to refer to illegal program actions that can result in 15 | arbitrary results. In short, "undefined behavior" is always a bug and 16 | never something you should do. See the [Rust 17 | reference](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) 18 | and the [entry in the Unsafe Code Guidelines glossary][ucg-ub] for more details. 19 | 20 | [ucg-ub]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#undefined-behavior 21 | 22 | Our usage of the term is generally the same as the [standard 23 | usage](https://en.wikipedia.org/wiki/Undefined_behavior) from other 24 | languages. 25 | 26 | 27 | 28 | ## LLVM-undefined behavior (LLVM-UB) 29 | 30 | We use the phrase **LLVM undefined behavior** to indicate things that 31 | are considered undefined behavior by LLVM itself. Barring bugs, the 32 | Rust compiler should never produce LLVM IR that contains LLVM-UB 33 | unless the behavior in question is *also* UB in Rust. Of course, there 34 | are bugs in the Rust compiler from time to time, and hence it can 35 | happen that we generate LLVM IR which contains LLVM-UB even if the 36 | corresponding Rust source code is meant to be fully defined (see 37 | e.g. [rust-lang/rust#28728]). The main reason it is worth separating 38 | LLVM-UB from the more general form of Rust UB is that, while both 39 | forms of UB can cause arbitrary things to happen in your 40 | code. However, as a practical measure, LLVM-UB is much more *likely 41 | to* in practice. 42 | 43 | [rust-lang/rust#28728]: https://github.com/rust-lang/rust/issues/28728 44 | 45 | 46 | 47 | ## Unspecified behavior 48 | 49 | We use the term "unspecified behavior" to refer to behavior that may 50 | vary across Rust releases, depending on what options are given to the 51 | compiler, or even -- in extreme cases -- across executions of the Rust 52 | compiler. However, unlike undefined behavior, the resulting execution 53 | is not completely undefined, and it must typically fall within some 54 | range of possibilities. Often, we will not specify precisely *how* 55 | something is implemented, but rather the patterns that must work. 56 | 57 | An example of "unspecified behavior" is the [layout for structs with 58 | no declared `#[repr]` attribute][ucg-struct]. This layout can and 59 | does change across Rust releases -- but of course within a given 60 | compilation, a struct must have *some* layout. Moreover, we guarantee 61 | that programs can (for example) use `sizeof` to determine the size of 62 | that layout, or access fields using Rust syntax like `foo.bar`. This 63 | requires the layout to be communicated in some fashion but doesn't 64 | specify how that is done. 65 | 66 | [ucg-struct]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/reference/src/layout/structs-and-tuples.md 67 | 68 | Our usage of the term is generally the same as the [standard 69 | usage](https://en.wikipedia.org/wiki/Unspecified_behavior) from other 70 | languages. 71 | 72 | --------------------------------------------------------------------------------