├── .gitignore ├── 0000-safer_transmute.md ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── release.toml ├── typic-derive ├── Cargo.toml └── src │ └── lib.rs └── typic ├── Cargo.toml ├── release.toml ├── src ├── lib.rs ├── private │ ├── bytelevel.rs │ ├── bytelevel │ │ ├── coproduct.rs │ │ ├── ops.rs │ │ ├── product.rs │ │ ├── slot.rs │ │ └── slot │ │ │ ├── array.rs │ │ │ ├── bytes.rs │ │ │ └── reference.rs │ ├── highlevel.rs │ ├── highlevel │ │ ├── coproduct.rs │ │ ├── field.rs │ │ └── product.rs │ ├── layout.rs │ ├── layout │ │ ├── aligned_to.rs │ │ ├── into_bytelevel.rs │ │ ├── into_bytelevel │ │ │ ├── field.rs │ │ │ ├── primitives.rs │ │ │ └── product.rs │ │ ├── padding.rs │ │ └── test.rs │ ├── num.rs │ ├── stability.rs │ ├── target.rs │ ├── transmute.rs │ └── transmute │ │ ├── from_layout.rs │ │ ├── from_layout │ │ ├── consume.rs │ │ └── flatten.rs │ │ ├── from_type.rs │ │ └── neglect.rs ├── transmute.rs └── transmute │ ├── safe_transmutation.rs │ └── unsafe_transmutation.rs └── tests ├── derive.rs ├── transmute.rs └── transmute_stress.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | .* 5 | !.gitignore 6 | -------------------------------------------------------------------------------- /0000-safer_transmute.md: -------------------------------------------------------------------------------- 1 | - Feature Name: `safer_transmute` 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 | # Summary 7 | [summary]: #summary 8 | 9 | A public API for statically-provable safe and sound transmutation between types. 10 | 11 | ***The examples in this RFC are fully implemented by [Typic](https://github.com/jswrenn/typic).*** For examples with type definitions, merely replace `#[repr(...)]` with `#[typic::repr(...)]`. 12 | 13 | # Motivation 14 | [motivation]: #motivation 15 | 16 | Why are we doing this? What use cases does it support? What is the expected outcome? 17 | 18 | # Guide-level explanation 19 | [guide-level-explanation]: #guide-level-explanation 20 | 21 | Transmutation is an operation that re-interprets bytes belonging to a value of one type (henceforth `T`) as if they were bytes belonging to a value of a different type (henceforth `U`). Rust provides three mechanisms for transmuting values: 22 | 23 | ## Types of Transmutation 24 | 25 | ### Unsound Transmutation (`transmute`, `transmute_copy`) 26 | The \[existing\] `mem::transmute` and `mem::transmute_copy` intrinsics allow for the ***unsafe*** and ***unsound*** transmutation between any `T` and `U`. 27 | 28 | These intrinsics are deeply unsafe. The Rust compiler will accept uses of these intrinsics even when `T` and `U` do not have well-defined layouts. ***Always use a [safe transmutation](#safe-transmutation) method instead, if possible.*** If you are unable to use a safe transmutation method, ***you may be relying on undefined compiler behavior***. 29 | 30 | ### Sound Transmutation (`sound_transmute`) 31 | The `mem::sound_transmute` function allows for the ***unsafe*** transmutation between `T` and `U`, when merely transmuting from `T` to `U` will not cause undefined behavior. For the key rules that govern when `T` is soundly convertible to `U`, see ***[When is a transmutation sound?][understanding-soundness]***. 32 | 33 | This operation is `unsafe`, as it will bypass any user-defined validity restrictions that `U` places on its fields and enforces with its constructors and methods. ***Always use a [safe transmutation](#safe-transmutation) method instead, if possible.*** If you are unable to use a safe transmutation method, you may be violating library invariants. 34 | 35 | ### Safe Transmutation (`TransmuteInto` and `TransmuteFrom`) 36 | The `TransmuteInto` trait is implemented for a types `T` and `U` if `T` is ***safely*** and ***soundly*** transmutable into `U`. This trait is only implemented when: 37 | 1. [`T` is soundly transmutable into `U`][understanding-soundness] 38 | 2. `U` does not have any inter-field validity constraints (i.e., it's `Transparent`) 39 | 40 | The `Transparent` marker trait indicates that a type does not have any inter-field validity requirements. This trait is implemented for all primitive types. 41 | 42 | The `Transparent` trait is implemented automatically for all `struct` and `enum` types whose fields have the same visibility as the type definition itself. These types are `Transparent` because anywhere the type is in scope, so to are its fields via the `.` operator. 43 | 44 | In cases where you do not wish to increase the visibility of your type's fields, you may manually implement this trait for your type. 45 | 46 | 47 | ## When is a transmutation sound? 48 | [understanding-soundness]: #when-is-a-transmutation-sound 49 | 50 | ### Well-Specified Representation 51 | Transmutation is ***always*** unsound if it occurs between types with unspecified representations. Most of Rust's primitive types have specified representations. That is, the layout characteristics of `u8`, `f32` and others are guaranteed to be stable across compiler versions. 52 | 53 | In contrast, most `struct` and `enum` types defined without an explicit `#[repr(C)]` or `#[repr(transparent)]` attribute do ***not*** have well-specified layout characteristics. 54 | 55 | To ensure that types you've define are soundly transmutable, you usually must mark them with the `#[repr(C)]` attribute. 56 | 57 | ### Transmuting Owned Values 58 | Transmutations into owned types must adhere to three conditions: 59 | 60 | #### Broadening (or Preserving) Bit Validity 61 | For each _ith_ of the destination type, all possible instantiations of the _ith_ byte of the source type must be a bit-valid instance of the _ith_ byte of the destination type. 62 | 63 | For example, we are permitted us to transmute a `NonZeroU8` into a `u8`: 64 | ```rust 65 | let _ : u8 = NonZeroU8::new(1).unwrap().transmute_into(); 66 | ``` 67 | ...because all possible instances of `NonZeroU8` are also valid instances of `u8`. However, transmuting a `u8` into a `NonZeroU8` is forbidden: 68 | ```rust 69 | let _ : NonZeroU8 = u8::default().transmute_into(); // Compile Error! 70 | ``` 71 | ...because not all instances of `u8` are valid instances of `NonZeroU8`. 72 | 73 | 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: 74 | ```rust 75 | #[repr(C)] 76 | #[derive(Default)] 77 | struct Padded(pub u8, pub u16, pub u8); 78 | 79 | #[repr(C)] 80 | #[derive(Default)] 81 | struct Packed(pub u16, pub u16, pub u16); 82 | 83 | assert_eq!(mem::size_of::(), mem::size_of::()); 84 | ``` 85 | 86 | We may safely transmute from `Packed` to `Padded`: 87 | ```rust 88 | let _ : Padded = Packed::default().transmute_into(); 89 | ``` 90 | ...but not from `Padded` to `Packed`: 91 | ```rust 92 | let _ : Packed = Padded::default().transmute_into(); // Compile Error! 93 | ``` 94 | ...because doing so would expose two uninitialized padding bytes in `Padded` as if they were initialized bytes in `Packed`. 95 | 96 | #### Shrinking (or Preserving) Size 97 | It's completely safe to transmute into a type with fewer bytes than the destination type; e.g.: 98 | ```rust 99 | let _ : u8 = u64::default().transmute_into(); 100 | ``` 101 | This transmute truncates away the final three bytes of the `u64` value. 102 | 103 | A value may ***not*** be transmuted into a type of greater size: 104 | ```rust 105 | let _ : u64 = u8::default().transmute_into(); // Compile Error! 106 | ``` 107 | 108 | 109 | ### Transmuting References 110 | The restrictions above that apply to transmuting owned values, also apply to transmuting references. However, references carry a few additional restrictions: 111 | 112 | #### Relaxing (or Preserving) Alignment 113 | You may transmute a reference into reference of more relaxed alignment: 114 | ```rust 115 | let _: &[u8; 0] = (&[0u16; 0]).transmute_into(); 116 | ``` 117 | 118 | However, you may **not** transmute a reference into a reference of stricter alignment: 119 | ```rust 120 | let _: &[u16; 0] = (&[0u8; 0]).transmute_into(); // Compile Error! 121 | ``` 122 | 123 | #### Shrinking (or Preserving) Lifetimes 124 | You may transmute a reference into reference of lesser lifetime: 125 | ```rust 126 | fn shrink<'a>() -> &'a u8 { 127 | static long : &'static u8 = &16; 128 | long 129 | } 130 | ``` 131 | 132 | However, you may **not** transmute a reference into a reference of greater lifetime: 133 | ```rust 134 | fn extend<'a>(short: &'a u8) -> &'static u8 { 135 | static long : &'static u8 = &16; 136 | short.transmute_into() 137 | } 138 | ``` 139 | 140 | #### Shrinking (or Preserving) Mutability 141 | You may preserve or decrease the mutability of a reference through transmutation: 142 | ```rust 143 | let _: &u8 = (&42u8).transmute_into(); 144 | let _: &u8 = (&mut 42u8).transmute_into(); 145 | ``` 146 | 147 | However, you may **not** transmute an immutable reference into a mutable reference: 148 | ```rust 149 | let _: &mut u8 = (&42u8).transmute_into(); // Compile Error! 150 | ``` 151 | 152 | #### Preserving Validity 153 | Unlike transmutations of owned values, the transmutation of a reference may also not expand the bit-validity of the referenced type. For instance: 154 | 155 | ```rust 156 | let mut x = NonZeroU8::new(42).unwrap(); 157 | { 158 | let y : &mut u8 = (&mut x).transmute_into(); // Compile Error! 159 | *y = 0; 160 | } 161 | 162 | let z : NonZeroU8 = x; 163 | ``` 164 | If this example did not produce a compile error, the value of `z` would not be a bit-valid instance of its type. 165 | 166 | # Reference-level explanation 167 | [reference-level-explanation]: #reference-level-explanation 168 | 169 | ## Library Additions 170 | 171 | ### `unsafe fn sound_transmute(T) -> U` 172 | 173 | ```rust 174 | pub unsafe fn sound_transmute(from: T) -> U 175 | where 176 | U: FromType, 177 | { 178 | let to = mem::transmute_copy(&from); 179 | mem::forget(from); 180 | to 181 | } 182 | ``` 183 | 184 | ### `unsafe trait Transparent` 185 | ```rust 186 | #[marker] 187 | pub unsafe trait Transparent {} 188 | ``` 189 | A type may implement the marker trait `Transparent` if it does not maintain any inter-field validity requirements. 190 | 191 | This trait is implemented automatically for `enum` and `struct` items whose fields all share the same visibility as the item itself. Such items cannot uphold interfield validity requirements via their constructors and methods, because any code where the item is visible can safely mutate its equally-visible fields via dot-access. 192 | 193 | ### `trait TransmuteFrom` 194 | `TransmuteFrom` allows for the **safe** transmutation of a value between two types. 195 | ```rust 196 | pub trait TransmuteFrom: Sized { 197 | /// Performs the conversion. 198 | fn transmute_from(from: T) -> Self; 199 | } 200 | ``` 201 | 202 | A type `T` is safely transmutable to a type `U` if both: 203 | 1. `U` does not maintain any inter-field validity requirements (`U: Transparent`) 204 | 2. Every instance of `T` is a bit-valid instance of `U` (`U: FromType`). 205 | 206 | Accordingly, we provide this blanket implementation: 207 | 208 | ```rust 209 | impl TransmuteFrom for U 210 | where 211 | U: Transparent + FromType, 212 | { 213 | #[inline(always)] 214 | fn transmute_from(from: T) -> U { 215 | unsafe { sound_transmute(from) } 216 | } 217 | } 218 | ``` 219 | 220 | 221 | ### `trait TransmuteInto` 222 | For consistency with [`From`]/[`Into`] and [`TryFrom`]/[`TryInto`], we provide the trait `TransmuteInto`, the reciprocal of `TransmuteFrom`: 223 | 224 | ```rust 225 | pub trait TransmuteInto: Sized { 226 | /// Performs the conversion. 227 | fn transmute_into(self) -> U; 228 | } 229 | ``` 230 | 231 | [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html 232 | [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html 233 | 234 | [`TryInto`]: https://doc.rust-lang.org/std/convert/trait.TryInto.html 235 | [`TryFrom`]: https://doc.rust-lang.org/std/convert/trait.TryFrom.html 236 | 237 | Accordingly, we provide this blanket implementation: 238 | 239 | ```rust 240 | impl TransmuteInto for T 241 | where 242 | U: TransmuteFrom, 243 | { 244 | #[inline(always)] 245 | fn transmute_into(self) -> U { 246 | U::transmute_from(self) 247 | } 248 | } 249 | ``` 250 | 251 | ### `unsafe trait FromType` (Perma-Unstable) 252 | ```rust 253 | #[marker] 254 | #[unstable] 255 | pub trait FromType {} 256 | ``` 257 | 258 | A type `U` is `FromType` if every possible instance of `T` is specified to be **soundly** transmutable into `U`. This trait shall be permenantly unstable. The compiler shall resolve whether `U: FromType` holds for two concrete types `U` and `T` during trait resolution. 259 | 260 | `FromType` shall be implemented incrementally and conservatively. 261 | 262 | # Drawbacks 263 | [drawbacks]: #drawbacks 264 | 265 | Increased compiler complexity. 266 | 267 | # Rationale and alternatives 268 | [rationale-and-alternatives]: #rationale-and-alternatives 269 | 270 | [`FromBits`]: https://internals.rust-lang.org/t/pre-rfc-frombits-intobits/7071 271 | [Safe Transmute v2]: https://internals.rust-lang.org/t/pre-rfc-v2-safe-transmute/11431 272 | [`Compatible`]: https://gist.github.com/gnzlbg/4ee5a49cc3053d8d20fddb04bc546000 273 | 274 | ## Familiar 275 | The public API defined by this proposal is consistent with Rust's existing core conversion traits, [`From`]/[`Into`] and [`TryFrom`]/[`TryInto`]. 276 | 277 | ## Conservative 278 | This proposal is conservative, only providing a public API transmutations whose soundness is _statically_ provable. Falliable conversions, such as `u8` to `bool` are not supported. 279 | 280 | In contrast, the [`Compatible`] proposal recommends the simultaneous addition of a `TryCompatible` trait for fallible conversions. 281 | 282 | ## Expressive and Incremental 283 | The public API defined by this proposal allows for the eventual support of safer transmutation in all cases that can be statically provably sound. The transmutations supported by this proposal may be incrementally increased without altering the public API by adding additional implementations of `FromType`. 284 | 285 | In contrast, in the [`FromBits`] and [Safe Transmute v2] proposal's: 286 | * `FromBits`/`FromAnyBytes` only supports conversions into types with validity no stricter than arbitrarily-initialized. 287 | * `IntoBits`/`ToBytes` only supports types without padding or other sources of uninitialized bytes. 288 | 289 | The expressive power of these traits cannot be substantially increased without providing a different public API for conversion. 290 | 291 | # Prior art 292 | [prior-art]: #prior-art 293 | 294 | TODO 295 | 296 | # Unresolved questions 297 | [unresolved-questions]: #unresolved-questions 298 | 299 | TODO 300 | 301 | # Future possibilities 302 | [future-possibilities]: #future-possibilities 303 | 304 | TODO -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | 8 | ## [Unreleased] - ReleaseDate 9 | ## [0.3.0] - 2020-06-30 10 | ## [0.2.3] - 2020-02-11 11 | ### Fixed 12 | - fix `bytelevel::Product` append operation 13 | - count padding bytes in field size 14 | - handling of `PNil→[{Bytes,Array}<_, U0>|...]` 15 | 16 | ## [0.2.2] - 2020-02-07 17 | ### Added 18 | - `#[no_std]` compatible. 19 | - [`GenericArray`](https://crates.io/crates/generic-array) support. 20 | - Expose `layout` module providing some of typic's type-level information about 21 | types (namely: size and minimum alignment). 22 | 23 | ## [0.2.1] - 2020-02-06 24 | ### Fixed 25 | - Removed unused, nightly-only feature. 26 | 27 | ## [0.2.0] - 2020-02-06 28 | ### Breaking Changes 29 | - Everything. This is a complete rewrite. 30 | 31 | ## 0.1.0 - 2019-12-28 32 | ### Added 33 | - Initial, prototype release. 34 | 35 | 36 | [Unreleased]: https://github.com/jswrenn/typic/compare/{{tag_name}}...HEAD 37 | [0.3.0]: https://github.com/jswrenn/typic/compare/{{tag_name}}...{{tag_name}} 38 | [0.2.3]: https://github.com/jswrenn/typic/compare/{{tag_name}}...{{tag_name}} 39 | [0.2.2]: https://github.com/typic/compare/typic-v0.2.1...{{tag_name}} 40 | [0.2.1]: https://github.com/jswrenn/typic/compare/typic-v0.2.0...typic-v0.2.1 41 | [0.2.0]: https://github.com/jswrenn/typic/releases/tag/typic-v0.2.0 42 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "typic-derive", 4 | "typic", 5 | ] 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **ANNOUNCEMENT:** The primary purpose of Typic was to prototype zero-compromise designs for a safe transmute language feature. [Read the resulting RFC draft here](https://github.com/rust-lang/project-safe-transmute/pull/5)! 2 | 3 | --- 4 | 5 | # Typic 6 | Typic helps you transmute fearlessly. It worries about the subtleties of 7 | ***[soundness]*** and ***[safety]*** so you don't have to! 8 | 9 | [![Documentation](https://docs.rs/typic/badge.svg)](https://docs.rs/typic/) 10 | [![Crates.io](https://img.shields.io/crates/v/typic.svg)](https://crates.io/crates/typic/0.1.0) 11 | 12 | Just import it and replace your `#[repr(...)]` attributes with `#[typic::repr(...)]`: 13 | ```rust 14 | // Import it! 15 | use typic::{self, TransmuteInto}; 16 | 17 | // Update your attributes! 18 | #[typic::repr(C)] 19 | pub struct Foo(pub u8, pub u16); 20 | 21 | // Transmute fearlessly! 22 | let _ : Foo = u32::default().transmute_into(); // Alchemy achieved! 23 | let _ : u32 = Foo::default().transmute_into(); // Compiler Error! 24 | ``` 25 | 26 | [soundness]: https://docs.rs/typic/latest/typic/transmute/unsafe_transmutation 27 | [safety]: https://docs.rs/typic/latest/typic/safe/ 28 | 29 | #### License 30 | 31 | 32 | Licensed under either of Apache License, Version 33 | 2.0 or MIT license at your option. 34 | 35 | 36 |
37 | 38 | 39 | Unless you explicitly state otherwise, any contribution intentionally submitted 40 | for inclusion in this crate by you, as defined in the Apache-2.0 license, shall 41 | be dual licensed as above, without any additional terms or conditions. 42 | 43 | -------------------------------------------------------------------------------- /release.toml: -------------------------------------------------------------------------------- 1 | pre-release-commit-message = "chore({{crate_name}}): Release {{version}}" 2 | no-dev-version = true 3 | -------------------------------------------------------------------------------- /typic-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "typic-derive" 3 | version = "0.3.0" 4 | authors = ["Jack Wrenn "] 5 | edition = "2018" 6 | license = "MIT/Apache-2.0" 7 | repository = "https://github.com/jswrenn/typic" 8 | description = "Type-safe transmutations between layout-compatible types." 9 | readme = "../README.md" 10 | 11 | [lib] 12 | proc-macro = true 13 | 14 | [dependencies] 15 | if_chain ="1.0" 16 | proc-macro2 = "1.0" 17 | quote = "1.0" 18 | 19 | [dependencies.syn] 20 | version = "1.0" 21 | features = ["full", "extra-traits", "visit"] 22 | -------------------------------------------------------------------------------- /typic-derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(warnings)] 2 | extern crate proc_macro; 3 | 4 | use if_chain::*; 5 | use proc_macro::TokenStream; 6 | use proc_macro2::TokenStream as TokenStream2; 7 | use quote::*; 8 | use std::cmp::Ord; 9 | use std::cmp::{max, min}; 10 | use syn; 11 | use syn::visit::Visit; 12 | use syn::{parse_macro_input, parse_quote}; 13 | use syn::{Attribute, Lit, Meta, NestedMeta, Visibility}; 14 | 15 | #[proc_macro_derive(StableABI)] 16 | pub fn stable_abi(input: TokenStream) -> TokenStream { 17 | use syn::DeriveInput; 18 | let DeriveInput { 19 | ident, 20 | generics, 21 | .. 22 | } = parse_macro_input!(input as DeriveInput); 23 | 24 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 25 | (quote! { 26 | unsafe impl #impl_generics typic::stability::TransmutableFrom 27 | for #ident #ty_generics #where_clause 28 | { 29 | type Type = Self; 30 | } 31 | 32 | unsafe impl #impl_generics typic::stability::TransmutableInto 33 | for #ident #ty_generics #where_clause 34 | { 35 | type Type = Self; 36 | } 37 | 38 | }).into() 39 | } 40 | 41 | #[proc_macro_attribute] 42 | pub fn typicrepr(_args: TokenStream, input: TokenStream) -> TokenStream { 43 | repr(_args, input) 44 | } 45 | 46 | fn impl_struct(definition: syn::ItemStruct) -> TokenStream { 47 | let name = &definition.ident; 48 | let attrs = &definition.attrs; 49 | let generics = &definition.generics; 50 | 51 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 52 | 53 | let all_public = definition.fields.iter().all(|field| { 54 | if let Visibility::Public(_) = field.vis { 55 | true 56 | } else { 57 | false 58 | } 59 | }); 60 | 61 | let mut repr = Repr::default(); 62 | attrs 63 | .into_iter() 64 | .for_each(|attr| repr.visit_attribute(attr)); 65 | 66 | if let Some(Method::Transparent) = repr.method { 67 | return (quote! { 68 | #definition 69 | 70 | impl #impl_generics typic::internal::Type 71 | for #name #ty_generics #where_clause 72 | { 73 | #[doc(hidden)] 74 | type ReprAlign = 75 | <#name #ty_generics as typic::internal::Type>::ReprAlign; 76 | 77 | #[doc(hidden)] 78 | type ReprPacked = 79 | <#name #ty_generics as typic::internal::Type>::ReprPacked; 80 | 81 | #[doc(hidden)] 82 | type HighLevel = 83 | <#name #ty_generics as typic::internal::Type>::HighLevel; 84 | } 85 | }) 86 | .into(); 87 | } 88 | 89 | let repr_align = repr 90 | .align 91 | .map(|n| format_ident!("U{}", n)) 92 | .unwrap_or(format_ident!("MinAlign")); 93 | 94 | let repr_packed = repr 95 | .packed 96 | .map(|n| format_ident!("U{}", n)) 97 | .unwrap_or(format_ident!("MaxAlign")); 98 | 99 | // no repr 100 | if let None = repr.method { 101 | return (quote! { 102 | #definition 103 | 104 | impl #impl_generics typic::internal::Type 105 | for #name #ty_generics #where_clause 106 | { 107 | #[doc(hidden)] type ReprAlign = typic::internal::#repr_align; 108 | #[doc(hidden)] type ReprPacked = typic::internal::#repr_packed; 109 | #[doc(hidden)] type HighLevel = Self; 110 | } 111 | }) 112 | .into(); 113 | } 114 | 115 | // otherwise, it's a C repr 116 | assert_eq!(repr.method, Some(Method::C)); 117 | 118 | let fields = definition 119 | .fields 120 | .iter() 121 | .rfold( 122 | quote! {typic::internal::PNil}, 123 | |rest, field| { 124 | let vis = if let Visibility::Public(_) = field.vis { 125 | format_ident!("Public") 126 | } else { 127 | format_ident!("Private") 128 | }; 129 | let field = field.ty.clone(); 130 | quote! { 131 | typic::internal::PCons< 132 | typic::internal::Field< 133 | typic::internal::field::#vis , 134 | #field>, 135 | #rest> 136 | } 137 | }, 138 | ); 139 | 140 | (quote! { 141 | #definition 142 | 143 | impl #impl_generics typic::internal::Type 144 | for #name #ty_generics #where_clause 145 | { 146 | #[doc(hidden)] type ReprAlign = typic::internal::#repr_align; 147 | #[doc(hidden)] type ReprPacked = typic::internal::#repr_packed; 148 | #[doc(hidden)] type HighLevel = #fields; 149 | } 150 | }) 151 | .into() 152 | } 153 | 154 | #[proc_macro_attribute] 155 | pub fn repr(args: TokenStream, input: TokenStream) -> TokenStream { 156 | let args: TokenStream2 = args.into(); 157 | let input: TokenStream2 = input.into(); 158 | let definition: syn::Item = parse_quote!(#[repr(#args)] #input); 159 | 160 | match definition { 161 | syn::Item::Struct(definition) => impl_struct(definition), 162 | _ => unimplemented!(), 163 | } 164 | } 165 | 166 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] 167 | enum Method { 168 | C, 169 | Packed, 170 | Transparent, 171 | } 172 | 173 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] 174 | enum Size { 175 | I8, 176 | I16, 177 | I32, 178 | I64, 179 | I128, 180 | ISize, 181 | U8, 182 | U16, 183 | U32, 184 | U64, 185 | U128, 186 | USize, 187 | } 188 | 189 | #[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] 190 | struct Repr { 191 | method: Option, 192 | align: Option, 193 | packed: Option, 194 | size: Option, 195 | } 196 | 197 | impl<'ast> Visit<'ast> for Repr { 198 | fn visit_attribute(&mut self, attr: &'ast Attribute) { 199 | if_chain! { 200 | if let Ok(Meta::List(meta_list)) = attr.parse_meta(); 201 | if let Some(ident) = meta_list.path.get_ident(); 202 | if ident.to_string() == "repr"; 203 | then { 204 | for meta in meta_list.nested { 205 | match meta { 206 | NestedMeta::Meta(Meta::Path(path)) => { 207 | let ident = (if let Some(ident) = path.get_ident() { 208 | ident.to_string() 209 | } else { 210 | continue; 211 | }); 212 | 213 | match &ident[..] { 214 | "C" => 215 | self.method = Some(Method::C), 216 | "transparent" => 217 | self.method = Some(Method::Transparent), 218 | 219 | "packed" => 220 | self.packed = self.packed.min(Some(1)), 221 | 222 | "i8" => self.size = Some(Size::I8), 223 | "i16" => self.size = Some(Size::I16), 224 | "i32" => self.size = Some(Size::I32), 225 | "i64" => self.size = Some(Size::I64), 226 | "i132" => self.size = Some(Size::I128), 227 | "isize" => self.size = Some(Size::ISize), 228 | "u8" => self.size = Some(Size::U8), 229 | "u16" => self.size = Some(Size::U16), 230 | "u32" => self.size = Some(Size::U32), 231 | "u64" => self.size = Some(Size::U64), 232 | "u132" => self.size = Some(Size::U128), 233 | "usize" => self.size = Some(Size::USize), 234 | _ => {}, 235 | } 236 | }, 237 | NestedMeta::Meta(Meta::List(meta_list)) => { 238 | if_chain! { 239 | if let Some(ident) = meta_list.path.get_ident(); 240 | if meta_list.nested.len() == 1; 241 | if let Some(n) = meta_list.nested.first(); 242 | if let NestedMeta::Lit(Lit::Int(n)) = n; 243 | let ident = ident.to_string(); 244 | if let Ok(n) = n.base10_parse::(); 245 | then { 246 | match &ident[..] { 247 | "align" => { 248 | self.align = self.align.max(Some(n)); 249 | }, 250 | "packed" => { 251 | self.packed = self.packed.min(Some(n)); 252 | } 253 | _ => {} 254 | } 255 | } 256 | } 257 | } 258 | _ => {}, 259 | } 260 | } 261 | } 262 | } 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /typic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "typic" 3 | version = "0.3.0" 4 | authors = ["Jack Wrenn "] 5 | edition = "2018" 6 | license = "MIT/Apache-2.0" 7 | repository = "https://github.com/jswrenn/typic" 8 | description = "Type-safe transmutations between layout-compatible types." 9 | readme = "../README.md" 10 | categories = ["rust-patterns", "no-std"] 11 | 12 | [dependencies] 13 | typenum = "1.10.0" 14 | typic-derive = { version = "^0.3.0", path = "../typic-derive" } 15 | generic-array = "0.13.2" 16 | 17 | [dev-dependencies] 18 | static_assertions = "1.1.0" 19 | -------------------------------------------------------------------------------- /typic/release.toml: -------------------------------------------------------------------------------- 1 | pre-release-commit-message = "chore({{crate_name}}): Release {{version}}" 2 | no-dev-version = true 3 | pre-release-replacements = [ 4 | {file="../CHANGELOG.md", search="Unreleased", replace="{{version}}"}, 5 | {file="../CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}"}, 6 | {file="../CHANGELOG.md", search="ReleaseDate", replace="{{date}}"}, 7 | {file="../CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate"}, 8 | {file="../CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/jswrenn/typic/compare/{{tag_name}}...HEAD"}, 9 | ] 10 | -------------------------------------------------------------------------------- /typic/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(warnings)] 3 | 4 | //! Typic helps you transmute fearlessly. It worries about the subtleties of 5 | //! ***[soundness]*** and ***[safety]*** so you don't have to! 6 | //! 7 | //! Just import it and replace your `#[repr(...)]` attributes with `#[typic::repr(...)]`: 8 | //! ``` 9 | //! // Import it! 10 | //! use typic::{self, transmute::StableTransmuteInto, stability::StableABI}; 11 | //! 12 | //! // Update your attributes! 13 | //! #[typic::repr(C)] 14 | //! #[derive(StableABI)] 15 | //! pub struct Foo(pub u8, pub u16); 16 | //! 17 | //! // Transmute fearlessly! 18 | //! let _ : Foo = 64u32.transmute_into(); // Alchemy achieved! 19 | //! ``` 20 | //! ```compile_fail 21 | //! # use typic::{self, TransmuteInto}; 22 | //! # #[typic::repr(C)] 23 | //! # #[derive(StableABI)] 24 | //! # struct Foo(pub u8, pub u16); 25 | //! let _ : u32 = Foo(16, 12).transmute_into(); // Compile Error! 26 | //! ``` 27 | //! 28 | //! [soundness]: crate::transmute::unsafe_transmutation#when-is-a-transmutation-sound 29 | //! [safety]: crate::transmute::safe_transmutation 30 | 31 | #[doc(hidden)] 32 | pub mod docs { 33 | pub mod prelude { 34 | pub use crate::stability::StableABI; 35 | pub use crate::transmute::{unsafe_transmute, StableTransmuteInto}; 36 | use crate::typic; 37 | pub use core::mem; 38 | pub use core::num::NonZeroU8; 39 | 40 | #[typic::repr(C)] 41 | #[derive(Default, StableABI)] 42 | pub struct Padded(pub u8, pub u16, pub u8); 43 | 44 | #[typic::repr(C)] 45 | #[derive(Default, StableABI)] 46 | pub struct Packed(pub u16, pub u16, pub u16); 47 | 48 | #[typic::repr(C)] 49 | #[derive(Default, StableABI)] 50 | pub struct Constrained { 51 | wizz: i8, 52 | bang: u8, 53 | } 54 | 55 | impl Constrained { 56 | /// the sum of `wizz` and `bang` must be greater than or equal to zero. 57 | pub fn new(wizz: i8, bang: u8) -> Self { 58 | assert!((wizz as i16) / (bang as i16) >= 0); 59 | Constrained { wizz, bang } 60 | } 61 | 62 | pub fn something_dangerous(&self) { 63 | unsafe { 64 | // do something that's only safe if `wizz + bang >= 0` 65 | } 66 | } 67 | } 68 | 69 | #[typic::repr(C)] 70 | #[derive(Default, StableABI)] 71 | pub struct Unconstrained { 72 | pub wizz: u8, 73 | pub bang: i8, 74 | } 75 | } 76 | } 77 | 78 | #[doc(hidden)] 79 | #[deprecated(note = "TODO")] 80 | pub enum TODO {} 81 | 82 | #[doc(hidden)] 83 | pub mod private { 84 | pub mod bytelevel; 85 | pub mod highlevel; 86 | pub mod layout; 87 | pub mod num; 88 | pub mod stability; 89 | pub mod target; 90 | pub mod transmute; 91 | } 92 | 93 | #[doc(hidden)] 94 | pub use private::highlevel as internal; 95 | 96 | /// Use `#[typic::repr(...)]` instead of `#[repr(...)]` on your type definitions. 97 | #[doc(inline)] 98 | pub use typic_derive::repr; 99 | 100 | #[doc(inline)] 101 | pub use private::stability; 102 | 103 | pub mod transmute; 104 | 105 | mod typic { 106 | pub use super::*; 107 | } 108 | 109 | /// Details about the layout of types. 110 | /// 111 | /// [`SizeOf`]: crate::layout::SizeOf 112 | /// [`zerocopy`]: https://crates.io/crates/zerocopy 113 | /// [`AsBytes`]: https://docs.rs/zerocopy/0.2.*/zerocopy/trait.AsBytes.html 114 | /// [`FromBytes`]: https://docs.rs/zerocopy/0.2.*/zerocopy/trait.FromBytes.html 115 | /// [`Unaligned`]: https://docs.rs/zerocopy/0.2.*/zerocopy/trait.Unaligned.html 116 | /// 117 | /// Useful for building your own abstractions over Typic. For instance, we can 118 | /// use [`SizeOf`] to implement [`zerocopy`]'s [`FromBytes`], [`AsBytes`] and 119 | /// [`Unaligned`] marker traits: 120 | /// 121 | /// ``` 122 | /// use typic::{layout::{Layout, SizeOf}, transmute::TransmuteInto, transmute::TransmuteFrom}; 123 | /// use generic_array::{ArrayLength as Length, GenericArray as Array}; 124 | /// use typenum::U1; 125 | /// 126 | /// /// Indicates `Self` can be produced from an 127 | /// /// appropriately-sized array of arbitrarily 128 | /// /// initialized bytes. 129 | /// pub trait FromBytes {} 130 | /// 131 | /// impl FromBytes for T 132 | /// where 133 | /// T: Layout, 134 | /// SizeOf: Length, 135 | /// T: TransmuteFrom>> 136 | /// {} 137 | /// 138 | /// /// Indicates `Self` can be converted into an 139 | /// /// appropriately-sized array of arbitrarily 140 | /// /// initialized bytes. 141 | /// pub trait AsBytes {} 142 | /// 143 | /// impl AsBytes for T 144 | /// where 145 | /// T: Layout, 146 | /// SizeOf: Length, 147 | /// T: TransmuteInto>> 148 | /// {} 149 | /// 150 | /// /// Indicates `Self` has no alignment requirement. 151 | /// pub trait Unaligned {} 152 | /// 153 | /// impl Unaligned for T 154 | /// where 155 | /// T: Layout, 156 | /// {} 157 | /// ``` 158 | pub mod layout { 159 | use crate::internal::{Private, Public}; 160 | use crate::private::{layout, num}; 161 | use generic_array::ArrayLength; 162 | 163 | /// Type-level information about type representation. 164 | pub trait Layout: layout::Layout { 165 | /// The size of `Self`. 166 | /// 167 | /// ``` 168 | /// use typenum::*; 169 | /// use static_assertions::*; 170 | /// use typic::layout::Layout; 171 | /// 172 | /// assert_type_eq_all!(U4, <[u16; 2] as Layout>::Size); 173 | /// ``` 174 | type Size: num::Unsigned + ArrayLength; 175 | 176 | /// The minimum alignment of `Self`. 177 | /// 178 | /// ``` 179 | /// use typenum::*; 180 | /// use static_assertions::*; 181 | /// use typic::layout::Layout; 182 | /// 183 | /// assert_type_eq_all!(U2, <[u16; 2] as Layout>::Align); 184 | /// ``` 185 | type Align: num::Unsigned; 186 | } 187 | 188 | impl Layout for T 189 | where 190 | T: layout::Layout, 191 | { 192 | type Size = >::Size; 193 | type Align = >::Align; 194 | } 195 | 196 | /// Get the size of `T` (if `T: Layout`). 197 | /// 198 | /// ``` 199 | /// use typenum::*; 200 | /// use static_assertions::*; 201 | /// use typic::layout::SizeOf; 202 | /// 203 | /// assert_type_eq_all!(U4, SizeOf<[u16; 2]>); 204 | /// ``` 205 | pub type SizeOf = ::Size; 206 | 207 | /// Get the minimum alignment of `T` (if `T: Layout`). 208 | /// 209 | /// ``` 210 | /// use typenum::*; 211 | /// use static_assertions::*; 212 | /// use typic::layout::AlignOf; 213 | /// 214 | /// assert_type_eq_all!(U2, AlignOf<[u16; 2]>); 215 | /// ``` 216 | pub type AlignOf = ::Align; 217 | } 218 | 219 | /// Examples demonstrating typic's ability to express common abstractions. 220 | pub mod extras { 221 | 222 | /// [Zerocopy](https://docs.rs/zerocopy)-style marker traits. 223 | pub mod zerocopy { 224 | use crate::layout::*; 225 | use crate::transmute::*; 226 | use typenum::U1; 227 | use generic_array::{ArrayLength as Length, GenericArray as Array}; 228 | 229 | /// Indicates `Self` can be produced from an 230 | /// appropriately-sized array of arbitrarily 231 | /// initialized bytes. 232 | pub unsafe trait FromBytes 233 | {} 234 | 235 | unsafe impl FromBytes for T 236 | where 237 | T: Layout + TransmuteFrom>, O> 238 | {} 239 | 240 | 241 | /// Indicates `Self` can be converted into an 242 | /// appropriately-sized array of arbitrarily 243 | /// initialized bytes. 244 | pub unsafe trait AsBytes {} 245 | 246 | unsafe impl AsBytes for T 247 | where 248 | T: Layout + TransmuteInto>, O> 249 | {} 250 | 251 | 252 | /// Indicates `Self` has no alignment requirement. 253 | pub trait Unaligned {} 254 | 255 | impl Unaligned for T 256 | where 257 | T: Layout, 258 | {} 259 | } 260 | 261 | /// [Bytemuck](https://docs.rs/bytemuck)-style casting functions. 262 | pub mod bytemuck { 263 | use crate::transmute::*; 264 | use core::mem::{align_of, size_of, size_of_val}; 265 | 266 | /// Try to convert a `&T` into `&U`. 267 | /// 268 | /// This produces `None` if the referent isn't appropriately 269 | /// aligned, as required by the destination type. 270 | /// 271 | /// Like [`bytemuck::try_cast_ref`], except that invariant 272 | /// that `T` and `U` have the same size is statically enforced. 273 | /// 274 | /// [`bytemuck::try_cast_ref`]: https://docs.rs/bytemuck/1.2.0/bytemuck/fn.try_cast_ref.html 275 | pub fn try_cast_ref<'t, 'u, T, U>(src: &'t T) -> Option<&'u U> 276 | where 277 | &'t T: UnsafeTransmuteInto<&'u U, neglect::Alignment>, 278 | { 279 | if align_of::() > align_of::() && (src as *const T as usize) % align_of::() != 0 { 280 | None 281 | } else { 282 | // Sound, because we dynamically enforce the alignment 283 | // requirement, whose static check we chose to neglect. 284 | Some(unsafe { src.unsafe_transmute_into() }) 285 | } 286 | } 287 | 288 | use core::slice; 289 | use generic_array::{ArrayLength as Length, GenericArray as Array}; 290 | use crate::layout::*; 291 | 292 | /// Try to convert a `&T` into `&U`. 293 | /// 294 | /// This produces `None` if the referent isn't appropriately 295 | /// aligned, as required by the destination type. 296 | /// 297 | /// Like [`bytemuck::try_cast_slice`], except that invariant 298 | /// that `T` and `U` have the same size is statically enforced. 299 | /// 300 | /// If const generics were stable, the trait bound would 301 | /// be instead written as just: 302 | /// ```ignore 303 | /// &'t [T; size_of::()]: 304 | /// TransmuteInto<&'u [U; size_of::()]> 305 | /// ``` 306 | /// 307 | /// [`bytemuck::try_cast_slice`]: https://docs.rs/bytemuck/1.2.0/bytemuck/fn.try_cast_slice.html 308 | pub fn try_cast_slice<'t, 'u, T, U>(src: &'t [T]) -> Option<&'u [U]> 309 | where 310 | &'t Array>: TransmuteInto<&'u Array>>, 311 | 312 | T: Layout, 313 | U: Layout, 314 | SizeOf: 'u + Length, 315 | SizeOf: 't + Length, 316 | { 317 | if align_of::() > align_of::() && (src.as_ptr() as usize) % align_of::() != 0 { 318 | None 319 | } else { 320 | let len = size_of_val(src).checked_div(size_of::()).unwrap_or(0); 321 | Some(unsafe { 322 | slice::from_raw_parts(src.as_ptr() as *const U, len) 323 | }) 324 | } 325 | } 326 | } 327 | } -------------------------------------------------------------------------------- /typic/src/private/bytelevel.rs: -------------------------------------------------------------------------------- 1 | //! The byte-level representation of a type. 2 | 3 | pub mod coproduct; 4 | pub mod ops; 5 | pub mod product; 6 | pub mod slot; 7 | 8 | pub use ops::{Add, Sum}; 9 | pub use product::{Cons as PCons, Nil as PNil}; 10 | 11 | use crate::private::num::{Sub1, U1}; 12 | use crate::private::target::PointerWidth; 13 | 14 | #[cfg(target_endian = "little")] 15 | pub type NonZeroSeq = 16 | PCons, PCons>, Rest>>; 17 | 18 | #[cfg(target_endian = "big")] 19 | pub type NonZeroSeq = 20 | PCons, PCons>, Rest>>; 21 | 22 | pub type ReferenceBytes = NonZeroSeq; 23 | -------------------------------------------------------------------------------- /typic/src/private/bytelevel/coproduct.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | pub trait Coproduct {} 4 | 5 | pub struct Nil; 6 | 7 | impl Coproduct for Nil {} 8 | 9 | pub struct Cons(PhantomData<(H, T)>); 10 | 11 | impl Coproduct for Cons {} 12 | -------------------------------------------------------------------------------- /typic/src/private/bytelevel/ops.rs: -------------------------------------------------------------------------------- 1 | //! Type-level operations on byte-level stuff. 2 | 3 | use crate::private::bytelevel::slot::*; 4 | use crate::private::bytelevel::{product::Product, PCons, PNil}; 5 | use crate::private::num; 6 | 7 | pub trait Add { 8 | type Output; 9 | } 10 | 11 | pub type Sum = >::Output; 12 | 13 | impl Add for Bytes { 14 | type Output = PNil; 15 | } 16 | 17 | /// `Bytes<_, N> + PNil = Bytes<_, N>`, where `N > 0`. 18 | impl Add for Bytes> { 19 | type Output = PCons; 20 | } 21 | 22 | impl Add> for Bytes { 23 | type Output = PCons; 24 | } 25 | 26 | /// `Bytes<_, N> + PNil = Bytes<_, N>`, where `N > 0`. 27 | impl Add> for Bytes> { 28 | type Output = PCons>; 29 | } 30 | 31 | impl Add for P { 32 | type Output = Self; 33 | } 34 | 35 | impl Add> for PNil 36 | where 37 | { 38 | type Output = PCons; 39 | } 40 | 41 | impl Add> for PCons 42 | where 43 | LT: Add>, 44 | { 45 | type Output = PCons>>::Output>; 46 | } 47 | -------------------------------------------------------------------------------- /typic/src/private/bytelevel/product.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | pub trait Product {} 4 | 5 | pub struct Nil; 6 | 7 | impl Product for Nil {} 8 | 9 | pub struct Cons(PhantomData<(H, T)>); 10 | 11 | impl Product for Cons {} 12 | -------------------------------------------------------------------------------- /typic/src/private/bytelevel/slot.rs: -------------------------------------------------------------------------------- 1 | pub mod array; 2 | pub mod bytes; 3 | pub mod reference; 4 | 5 | pub use array::Array; 6 | pub use bytes::Bytes; 7 | pub use reference::{Reference, Shared, SharedRef, Unique, UniqueRef}; 8 | 9 | /// The data is from a `pub` field 10 | pub type Pub = crate::internal::Public; 11 | 12 | /// The field is from a field that is not `pub`. 13 | pub type Priv = crate::internal::Private; 14 | 15 | pub type PaddingSlot = Bytes; 16 | pub type InitializedSlot = Bytes; 17 | pub type NonZeroSlot = Bytes; 18 | -------------------------------------------------------------------------------- /typic/src/private/bytelevel/slot/array.rs: -------------------------------------------------------------------------------- 1 | //! [T; N] 2 | use core::marker::PhantomData; 3 | 4 | /// A unique reference to a type `T` with lifetime `'a`. 5 | pub struct Array(PhantomData<(Visibility, T, N)>); 6 | -------------------------------------------------------------------------------- /typic/src/private/bytelevel/slot/bytes.rs: -------------------------------------------------------------------------------- 1 | //! Non-reference slots. 2 | use core::marker::PhantomData; 3 | 4 | /// A sequence of bytes of `Kind` and `Size`. 5 | pub struct Bytes(PhantomData<(Vis, Kind, Size)>); 6 | 7 | /// Markers indicating the kind of bit-level validity restrictions that exist 8 | /// on a `Bytes`. 9 | pub mod kind { 10 | /// The byte(s) must be initialized to a non-zero value. 11 | pub struct NonZero; 12 | 13 | /// The byte(s) must be initialized to any value. 14 | pub struct Initialized; 15 | 16 | /// The byte(s) may be uninitialized or initialized. 17 | pub struct Uninitialized; 18 | } 19 | -------------------------------------------------------------------------------- /typic/src/private/bytelevel/slot/reference.rs: -------------------------------------------------------------------------------- 1 | //! `& T` and `&mut T` 2 | 3 | use core::marker::PhantomData; 4 | 5 | pub struct Shared; 6 | pub struct Unique; 7 | 8 | pub struct Reference<'a, Visibility, K, T>(PhantomData<(Visibility, K, &'a T)>); 9 | 10 | /// A unique reference to a type `T` with lifetime `'a`. 11 | pub type UniqueRef<'a, Visibility, T> = Reference<'a, Visibility, Unique, T>; 12 | 13 | /// A shared reference to a type `T` with lifetime `'a`. 14 | pub type SharedRef<'a, Visibility, T> = Reference<'a, Visibility, Shared, T>; 15 | -------------------------------------------------------------------------------- /typic/src/private/highlevel.rs: -------------------------------------------------------------------------------- 1 | //! Types for encoding the high-level representation of a type's structure. 2 | 3 | pub mod coproduct; 4 | pub mod product; 5 | pub mod field; 6 | 7 | use crate::private::num::Unsigned; 8 | 9 | #[doc(hidden)] 10 | pub use typenum::consts::*; 11 | 12 | #[doc(inline)] 13 | pub use field::{Field, Public, Private}; 14 | 15 | #[doc(inline)] 16 | pub use coproduct::{Cons as CCons, Nil as CNil}; 17 | #[doc(inline)] 18 | pub use product::{Cons as PCons, Nil as PNil}; 19 | 20 | pub type MinAlign = U1; 21 | pub type MaxAlign = U536870912; 22 | 23 | /// Implemented for types whose structure is understood by typic. 24 | /// 25 | /// This trait is implemented for [many primitive types](#foreign-impls) and for 26 | /// user-defined types annotated with the `#[typic::repr(...)]` attribute. This 27 | /// trait should **not** be implemented manually. 28 | pub trait Type { 29 | /// `align(N)` 30 | type ReprAlign: Unsigned; 31 | 32 | /// `packed(N)` 33 | type ReprPacked: Unsigned; 34 | 35 | /// An abstract representation of the type's structure. 36 | type HighLevel; 37 | } 38 | 39 | pub(crate) type HighLevelOf = ::HighLevel; 40 | pub(crate) type ReprAlignOf = ::ReprAlign; 41 | pub(crate) type ReprPackedOf = ::ReprPacked; 42 | -------------------------------------------------------------------------------- /typic/src/private/highlevel/coproduct.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | pub trait Coproduct {} 4 | 5 | pub struct Nil; 6 | 7 | impl Coproduct for Nil {} 8 | 9 | pub struct Cons(PhantomData<(H, T)>); 10 | 11 | impl Coproduct for Cons {} 12 | -------------------------------------------------------------------------------- /typic/src/private/highlevel/field.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | use crate::private::num::Min; 3 | 4 | pub struct Public; 5 | pub struct Private; 6 | 7 | impl Min for Public { 8 | type Output = Public; 9 | fn min(self, rhs: Public) -> Self::Output {Public} 10 | } 11 | 12 | impl Min for Private { 13 | type Output = Private; 14 | fn min(self, rhs: Private) -> Self::Output {Private} 15 | } 16 | 17 | impl Min for Private { 18 | type Output = Private; 19 | fn min(self, rhs: Public) -> Self::Output {Private} 20 | } 21 | 22 | impl Min for Public { 23 | type Output = Private; 24 | fn min(self, rhs: Private) -> Self::Output {Private} 25 | } 26 | 27 | pub struct Field(PhantomData<(Vis, Type)>); -------------------------------------------------------------------------------- /typic/src/private/highlevel/product.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | pub trait Product {} 4 | 5 | pub struct Nil; 6 | 7 | impl Product for Nil {} 8 | 9 | pub struct Cons(PhantomData<(H, T)>); 10 | 11 | impl Product for Cons {} 12 | -------------------------------------------------------------------------------- /typic/src/private/layout.rs: -------------------------------------------------------------------------------- 1 | use crate::private::highlevel::{HighLevelOf, ReprAlignOf, ReprPackedOf, Type}; 2 | use crate::private::num::Unsigned; 3 | use generic_array::ArrayLength; 4 | 5 | mod aligned_to; 6 | 7 | mod into_bytelevel; 8 | mod padding; 9 | 10 | use crate::private::highlevel::Public; 11 | pub use aligned_to::AlignedTo; 12 | use into_bytelevel::IntoByteLevel; 13 | use padding::PaddingNeededForField; 14 | 15 | /// The actual memory layout characteristics of `Self`. 16 | pub trait Layout { 17 | /// The actual alignment of `Self`. 18 | type Align: Unsigned; 19 | 20 | /// The actual size of `Self`. 21 | type Size: Unsigned + ArrayLength; 22 | 23 | /// The byte-level representation of `Self`. 24 | type ByteLevel; 25 | } 26 | 27 | #[rustfmt::skip] 28 | impl Layout for T 29 | where 30 | T: Type, 31 | 32 | HighLevelOf: 33 | IntoByteLevel< 34 | ReprAlignOf, 35 | ReprPackedOf, 36 | Visibility, 37 | >, 38 | 39 | as IntoByteLevel< 40 | ReprAlignOf, 41 | ReprPackedOf, 42 | Visibility, 43 | >>::Offset: ArrayLength, 44 | { 45 | type Align = 46 | as IntoByteLevel< 47 | ReprAlignOf, 48 | ReprPackedOf, 49 | Visibility, 50 | >>::Align; 51 | 52 | type Size = 53 | as IntoByteLevel< 54 | ReprAlignOf, 55 | ReprPackedOf, 56 | Visibility, 57 | >>::Offset; 58 | 59 | type ByteLevel = 60 | as IntoByteLevel< 61 | ReprAlignOf, 62 | ReprPackedOf, 63 | Visibility, 64 | >>::Output; 65 | } 66 | 67 | #[cfg(test)] 68 | mod test; 69 | -------------------------------------------------------------------------------- /typic/src/private/layout/aligned_to.rs: -------------------------------------------------------------------------------- 1 | use super::Layout; 2 | use crate::private::num::*; 3 | use crate::internal::Public; 4 | 5 | pub trait AlignedTo {} 6 | 7 | impl AlignedTo for U 8 | where 9 | T: Layout, 10 | U: Layout, 11 | >::Align: PartialDiv<>::Align>, 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /typic/src/private/layout/into_bytelevel.rs: -------------------------------------------------------------------------------- 1 | //! Compute the byte-level layout from a generic representation of a type. 2 | 3 | use crate::private::num::{Unsigned, U0}; 4 | 5 | pub mod field; 6 | pub mod primitives; 7 | pub mod product; 8 | 9 | pub trait IntoByteLevel { 10 | /// The byte-level representation of the type. 11 | type Output; 12 | 13 | /// The size of the type. 14 | type Offset: Unsigned; 15 | 16 | /// The actual alignment of the type. 17 | type Align: Unsigned; 18 | } 19 | -------------------------------------------------------------------------------- /typic/src/private/layout/into_bytelevel/field.rs: -------------------------------------------------------------------------------- 1 | use crate::private::bytelevel::{slot::PaddingSlot, PCons}; 2 | use crate::private::layout::{Layout, PaddingNeededForField}; 3 | use crate::private::num::{self, Minimum, Min, Unsigned}; 4 | use crate::internal::Field; 5 | 6 | pub trait FieldIntoByteLevel { 7 | /// The padded, byte-level representation of `Self`. 8 | type Output; 9 | 10 | /// The offset immediately following `Self`. 11 | type Offset: Unsigned; 12 | 13 | /// The alignment of this field. 14 | type Align: Unsigned; 15 | } 16 | 17 | impl FieldIntoByteLevel for Field 18 | where 19 | F: Layout> + PaddingNeededForField, Offset, Packed>, 20 | V: Min, 21 | Offset: num::Add<, Offset, Packed>>::Output>, 22 | 23 | num::Sum, Offset, Packed>>::Output>: 24 | num::Add<>>::Size>, 25 | 26 | num::Sum< 27 | num::Sum, Offset, Packed>>::Output>, 28 | >>::Size 29 | >: Unsigned, 30 | 31 | Packed: num::Min<>>::Align>, 32 | num::Minimum>>::Align>: Unsigned, 33 | { 34 | type Output = PCons< 35 | PaddingSlot, Offset, Packed>>::Output>, 36 | >>::ByteLevel, 37 | >; 38 | 39 | type Offset = num::Sum< 40 | num::Sum, Offset, Packed>>::Output>, 41 | >>::Size 42 | >; 43 | 44 | type Align = num::Minimum>>::Align>; 45 | } 46 | -------------------------------------------------------------------------------- /typic/src/private/layout/into_bytelevel/primitives.rs: -------------------------------------------------------------------------------- 1 | use crate::stability::*; 2 | use super::IntoByteLevel; 3 | use crate::private::bytelevel::{ 4 | slot::{Array, InitializedSlot, SharedRef, UniqueRef}, 5 | NonZeroSeq, PCons, PNil, ReferenceBytes, 6 | }; 7 | use crate::private::highlevel::{MaxAlign, MinAlign}; 8 | use crate::private::highlevel::Type; 9 | use crate::private::layout::Layout; 10 | 11 | use crate::private::num::*; 12 | use crate::private::target::PointerWidth; 13 | 14 | use crate::stability::{self, TransmutableInto, TransmutableFrom}; 15 | 16 | macro_rules! primitive_layout { 17 | ($($ty: ty { size: $size: ty, align: $align: ty };)*) => { 18 | $( 19 | impl Type for $ty { 20 | #[doc(hidden)] type ReprAlign = $align; 21 | #[doc(hidden)] type ReprPacked = $align; 22 | #[doc(hidden)] type HighLevel = Self; 23 | } 24 | 25 | unsafe impl TransmutableFrom for $ty { 26 | type Type = Self; 27 | } 28 | 29 | unsafe impl TransmutableInto for $ty { 30 | type Type = Self; 31 | } 32 | 33 | impl IntoByteLevel for $ty 34 | where 35 | Offset: Add<$size>, 36 | Sum: Unsigned, 37 | { 38 | type Output = PCons, PNil>; 39 | type Offset = Sum; 40 | type Align = $align; 41 | } 42 | )* 43 | } 44 | } 45 | 46 | primitive_layout! { 47 | u8 { size: U1, align: U1 }; 48 | u16 { size: U2, align: U2 }; 49 | u32 { size: U4, align: U4 }; 50 | u64 { size: U8, align: U8 }; 51 | u128 { size: U16, align: U16 }; 52 | i8 { size: U1, align: U1 }; 53 | i16 { size: U2, align: U2 }; 54 | i32 { size: U4, align: U4 }; 55 | i64 { size: U8, align: U8 }; 56 | i128 { size: U16, align: U16 }; 57 | isize { size: PointerWidth, align: PointerWidth }; 58 | usize { size: PointerWidth, align: PointerWidth }; 59 | f32 { size: U4, align: U4 }; 60 | f64 { size: U8, align: U8 }; 61 | } 62 | 63 | use core::sync::atomic::*; 64 | 65 | primitive_layout! { 66 | AtomicU8 { size: U1, align: U1 }; 67 | AtomicU16 { size: U2, align: U2 }; 68 | AtomicU32 { size: U4, align: U4 }; 69 | AtomicU64 { size: U8, align: U8 }; 70 | AtomicUsize { size: PointerWidth, align: PointerWidth }; 71 | AtomicI8 { size: U1, align: U1 }; 72 | AtomicI16 { size: U2, align: U2 }; 73 | AtomicI32 { size: U4, align: U4 }; 74 | AtomicI64 { size: U8, align: U8 }; 75 | AtomicIsize { size: PointerWidth, align: PointerWidth }; 76 | } 77 | 78 | macro_rules! nonzero_layout { 79 | ($($ty: ty { size: $size: ty, align: $align: ty };)*) => { 80 | $( 81 | impl Type for $ty { 82 | #[doc(hidden)] type ReprAlign = $align; 83 | #[doc(hidden)] type ReprPacked = $align; 84 | #[doc(hidden)] type HighLevel = Self; 85 | } 86 | 87 | unsafe impl TransmutableFrom for $ty { 88 | type Type = Self; 89 | } 90 | 91 | unsafe impl TransmutableInto for $ty { 92 | type Type = Self; 93 | } 94 | 95 | impl IntoByteLevel for $ty 96 | where 97 | Offset: Add<$size>, 98 | Sum: Unsigned, 99 | { 100 | type Output = NonZeroSeq; 101 | type Offset = Sum; 102 | type Align = $align; 103 | } 104 | )* 105 | } 106 | } 107 | 108 | use core::num::*; 109 | 110 | nonzero_layout! { 111 | NonZeroU8 { size: U1, align: U1 }; 112 | NonZeroU16 { size: U2, align: U2 }; 113 | NonZeroU32 { size: U4, align: U4 }; 114 | NonZeroU64 { size: U8, align: U8 }; 115 | NonZeroU128 { size: U16, align: U16 }; 116 | NonZeroI8 { size: U1, align: U1 }; 117 | NonZeroI16 { size: U2, align: U2 }; 118 | NonZeroI32 { size: U4, align: U4 }; 119 | NonZeroI64 { size: U8, align: U8 }; 120 | NonZeroI128 { size: U16, align: U16 }; 121 | NonZeroIsize { size: PointerWidth, align: PointerWidth }; 122 | NonZeroUsize { size: PointerWidth, align: PointerWidth }; 123 | } 124 | 125 | #[rustfmt::skip] 126 | impl Type for () { 127 | #[doc(hidden)] type ReprAlign = PointerWidth; 128 | #[doc(hidden)] type ReprPacked = PointerWidth; 129 | #[doc(hidden)] type HighLevel = Self; 130 | } 131 | 132 | unsafe impl TransmutableFrom for () { 133 | type Type = Self; 134 | } 135 | 136 | unsafe impl TransmutableInto for () { 137 | type Type = Self; 138 | } 139 | 140 | impl IntoByteLevel for () 141 | where 142 | Offset: Unsigned, 143 | PointerWidth: Unsigned, 144 | { 145 | type Output = PNil; 146 | type Offset = Offset; 147 | type Align = PointerWidth; 148 | } 149 | 150 | unsafe impl<'a, T> TransmutableFrom for &'a T 151 | { 152 | type Type = Self; 153 | } 154 | 155 | unsafe impl<'a, T> TransmutableInto for &'a T 156 | { 157 | type Type = Self; 158 | } 159 | 160 | #[rustfmt::skip] 161 | impl<'a, T> Type for &'a T { 162 | #[doc(hidden)] type ReprAlign = PointerWidth; 163 | #[doc(hidden)] type ReprPacked = PointerWidth; 164 | #[doc(hidden)] type HighLevel = Self; 165 | } 166 | 167 | impl<'a, ReprAlign, ReprPacked, Visibility, Offset, T> IntoByteLevel for &'a T 168 | where 169 | Offset: Add, 170 | Sum: Unsigned, 171 | { 172 | type Output = PCons, PNil>; 173 | type Offset = Sum; 174 | type Align = PointerWidth; 175 | } 176 | 177 | unsafe impl<'a, T> TransmutableFrom for &'a mut T 178 | { 179 | type Type = Self; 180 | } 181 | 182 | unsafe impl<'a, T> TransmutableInto for &'a mut T 183 | { 184 | type Type = Self; 185 | } 186 | 187 | #[rustfmt::skip] 188 | impl<'a, T> Type for &'a mut T { 189 | #[doc(hidden)] type ReprAlign = PointerWidth; 190 | #[doc(hidden)] type ReprPacked = PointerWidth; 191 | #[doc(hidden)] type HighLevel = Self; 192 | } 193 | 194 | impl<'a, ReprAlign, ReprPacked, Visibility, Offset, T> IntoByteLevel 195 | for &'a mut T 196 | where 197 | Offset: Add, 198 | Sum: Unsigned, 199 | { 200 | type Output = PCons, PNil>; 201 | type Offset = Sum; 202 | type Align = PointerWidth; 203 | } 204 | 205 | unsafe impl TransmutableFrom for *const T { 206 | type Type = Self; 207 | } 208 | 209 | unsafe impl TransmutableInto for *const T { 210 | type Type = Self; 211 | } 212 | 213 | #[rustfmt::skip] 214 | impl Type for *const T { 215 | #[doc(hidden)] type ReprAlign = PointerWidth; 216 | #[doc(hidden)] type ReprPacked = PointerWidth; 217 | #[doc(hidden)] type HighLevel = Self; 218 | } 219 | 220 | impl IntoByteLevel for *const T 221 | where 222 | Offset: Add, 223 | Sum: Unsigned, 224 | { 225 | type Output = ReferenceBytes; 226 | type Offset = Sum; 227 | type Align = PointerWidth; 228 | } 229 | 230 | unsafe impl TransmutableFrom for *mut T { 231 | type Type = Self; 232 | } 233 | 234 | unsafe impl TransmutableInto for *mut T { 235 | type Type = Self; 236 | } 237 | 238 | #[rustfmt::skip] 239 | impl Type for *mut T { 240 | #[doc(hidden)] type ReprAlign = PointerWidth; 241 | #[doc(hidden)] type ReprPacked = PointerWidth; 242 | #[doc(hidden)] type HighLevel = Self; 243 | } 244 | 245 | impl IntoByteLevel for *mut T 246 | where 247 | Offset: Add, 248 | Sum: Unsigned, 249 | { 250 | type Output = ReferenceBytes; 251 | type Offset = Sum; 252 | type Align = PointerWidth; 253 | } 254 | 255 | #[rustfmt::skip] 256 | impl Type for AtomicPtr { 257 | #[doc(hidden)] type ReprAlign = PointerWidth; 258 | #[doc(hidden)] type ReprPacked = PointerWidth; 259 | #[doc(hidden)] type HighLevel = Self; 260 | } 261 | 262 | unsafe impl TransmutableFrom for AtomicPtr { 263 | type Type = Self; 264 | } 265 | 266 | unsafe impl TransmutableInto for AtomicPtr { 267 | type Type = Self; 268 | } 269 | 270 | impl IntoByteLevel for AtomicPtr 271 | where 272 | Offset: Add, 273 | Sum: Unsigned, 274 | { 275 | type Output = ReferenceBytes; 276 | type Offset = Sum; 277 | type Align = PointerWidth; 278 | } 279 | 280 | use core::cell::{Cell, UnsafeCell}; 281 | 282 | #[rustfmt::skip] 283 | impl Type for Cell 284 | where 285 | T: Type, 286 | { 287 | #[doc(hidden)] type ReprAlign = ::ReprAlign; 288 | #[doc(hidden)] type ReprPacked = ::ReprPacked; 289 | #[doc(hidden)] type HighLevel = ::HighLevel; 290 | } 291 | 292 | unsafe impl TransmutableFrom for Cell 293 | { 294 | type Type = ::Type; 295 | } 296 | 297 | unsafe impl TransmutableInto for Cell 298 | { 299 | type Type = ::Type; 300 | } 301 | 302 | #[rustfmt::skip] 303 | impl Type for UnsafeCell 304 | where 305 | T: Type, 306 | { 307 | #[doc(hidden)] type ReprAlign = ::ReprAlign; 308 | #[doc(hidden)] type ReprPacked = ::ReprPacked; 309 | #[doc(hidden)] type HighLevel = ::HighLevel; 310 | } 311 | 312 | unsafe impl TransmutableInto for UnsafeCell 313 | { 314 | type Type = ::Type; 315 | } 316 | 317 | unsafe impl TransmutableFrom for UnsafeCell 318 | { 319 | type Type = ::Type; 320 | } 321 | 322 | macro_rules! array_layout { 323 | ($($n: expr, $t: ty);*) => { 324 | $( 325 | impl Type for [T; $n] { 326 | #[doc(hidden)] type ReprAlign = MinAlign; 327 | #[doc(hidden)] type ReprPacked = MaxAlign; 328 | #[doc(hidden)] type HighLevel = Self; 329 | } 330 | 331 | unsafe impl TransmutableFrom for [T; $n] 332 | where 333 | [::Type; $n]: Layout 334 | { 335 | type Type = [::Type; $n]; 336 | } 337 | 338 | unsafe impl TransmutableInto for [T; $n] 339 | where 340 | [::Type; $n]: Layout 341 | { 342 | type Type = [::Type; $n]; 343 | } 344 | 345 | impl IntoByteLevel 346 | for [T; $n] 347 | where 348 | T: Layout, 349 | $t: Mul<>::Size>, 350 | 351 | Offset: Add>::Size>>, 352 | Sum>::Size>>: Unsigned, 353 | { 354 | type Output = PCons, PNil>; 355 | type Offset = Sum>::Size>>; 356 | type Align = >::Align; 357 | } 358 | )* 359 | }; 360 | } 361 | 362 | array_layout![ 363 | 0, U0; 364 | 1, U1; 365 | 2, U2; 366 | 3, U3; 367 | 4, U4; 368 | 5, U5; 369 | 6, U6; 370 | 7, U7; 371 | 8, U8; 372 | 9, U9; 373 | 10, U10; 374 | 11, U11; 375 | 12, U12; 376 | 13, U13; 377 | 14, U14; 378 | 15, U15; 379 | 16, U16; 380 | 17, U17; 381 | 18, U18; 382 | 19, U19; 383 | 20, U20; 384 | 21, U21; 385 | 22, U22; 386 | 23, U23; 387 | 24, U24; 388 | 25, U25; 389 | 26, U26; 390 | 27, U27; 391 | 28, U28; 392 | 29, U29; 393 | 30, U30; 394 | 31, U31; 395 | 32, U32 396 | ]; 397 | 398 | use generic_array::{GenericArray, ArrayLength}; 399 | 400 | impl Type for GenericArray 401 | where 402 | N: ArrayLength, 403 | { 404 | #[doc(hidden)] type ReprAlign = MinAlign; 405 | #[doc(hidden)] type ReprPacked = MaxAlign; 406 | #[doc(hidden)] type HighLevel = Self; 407 | } 408 | 409 | unsafe impl TransmutableFrom for GenericArray 410 | where 411 | N: ArrayLength + ArrayLength<::Type>, 412 | T: TransmutableFrom, 413 | GenericArray<::Type, N>: Layout, 414 | { 415 | type Type = GenericArray<::Type, N>; 416 | } 417 | 418 | unsafe impl TransmutableInto for GenericArray 419 | where 420 | N: ArrayLength + ArrayLength<::Type>, 421 | T: TransmutableInto, 422 | GenericArray<::Type, N>: Layout, 423 | { 424 | type Type = GenericArray<::Type, N>; 425 | } 426 | 427 | impl IntoByteLevel 428 | for GenericArray 429 | where 430 | T: Layout, 431 | N: ArrayLength, 432 | N: Mul<>::Size>, 433 | 434 | Offset: Add>::Size>>, 435 | Sum>::Size>>: Unsigned, 436 | { 437 | type Output = PCons, PNil>; 438 | type Offset = Sum>::Size>>; 439 | type Align = >::Align; 440 | } 441 | -------------------------------------------------------------------------------- /typic/src/private/layout/into_bytelevel/product.rs: -------------------------------------------------------------------------------- 1 | //! Compute the byte-level layout of a product type. 2 | use super::field::FieldIntoByteLevel; 3 | use crate::private::bytelevel::{self, slot::PaddingSlot}; 4 | use crate::private::highlevel; 5 | use crate::private::layout::{padding::PadTo, IntoByteLevel}; 6 | use crate::private::num::{self, Unsigned}; 7 | 8 | #[rustfmt::skip] 9 | impl IntoByteLevel for highlevel::PNil 10 | where 11 | ReprAlign: Unsigned, 12 | Offset: PadTo + num::Add<>::Output>, 13 | 14 | num::Sum< 15 | Offset, 16 | >::Output 17 | >: Unsigned, 18 | { 19 | type Output = 20 | bytelevel::PCons< 21 | PaddingSlot>::Output>, 22 | bytelevel::PNil 23 | >; 24 | 25 | type Offset = 26 | num::Sum< 27 | Offset, 28 | >::Output 29 | >; 30 | 31 | type Align = ReprAlign; 32 | } 33 | 34 | #[rustfmt::skip] 35 | impl 36 | IntoByteLevel for highlevel::PCons 37 | where 38 | F: FieldIntoByteLevel, 39 | R: IntoByteLevel>::Align, 41 | ReprAlign, 42 | >, ReprPacked, Visibility, >::Offset>, 43 | 44 | >::Output: 45 | bytelevel::Add< 46 | >::Align, 49 | ReprAlign, 50 | >, 51 | ReprPacked, 52 | Visibility, 53 | >::Offset, 54 | >>::Output, 55 | >, 56 | 57 | >::Align: 58 | num::Max, 59 | 60 | num::Maximum< 61 | >::Align, 62 | ReprAlign, 63 | >: Unsigned, 64 | { 65 | type Output = 66 | bytelevel::Sum< 67 | >::Output, 68 | >::Align, 71 | ReprAlign, 72 | >, 73 | ReprPacked, 74 | Visibility, 75 | >::Offset, 76 | >>::Output, 77 | >; 78 | 79 | type Offset = 80 | >::Align, 83 | ReprAlign, 84 | >, 85 | ReprPacked, 86 | Visibility, 87 | >::Offset, 88 | >>::Offset; 89 | 90 | type Align = 91 | num::Maximum< 92 | >::Align, 93 | ReprAlign, 94 | >; 95 | } 96 | -------------------------------------------------------------------------------- /typic/src/private/layout/padding.rs: -------------------------------------------------------------------------------- 1 | use super::Layout; 2 | use crate::private::num::*; 3 | 4 | /// The amount of padding, counted in bytes, that must preceed `Self` in a 5 | /// compound type, where `Offset` is the index of the byte following the end of 6 | /// the preceeding field, and `Packed` is an unsigned integer reflecting the 7 | /// minimum packing of the enclosing type. 8 | pub trait PaddingNeededForField { 9 | type Output: Unsigned; 10 | } 11 | 12 | impl PaddingNeededForField for T 13 | where 14 | T: Layout, 15 | >::Align: Min, 16 | Minimum<>::Align, Packed>: Unsigned, 17 | Offset: PadTo>::Align, Packed>>, 18 | >::Align, Packed>>>::Output: Unsigned, 19 | { 20 | /// In the presence of a `repr(packed(N))` modifier, this field is packed 21 | /// to satisfy alignment `N` or the preferred alignment of `T`—whichever is 22 | /// lower. 23 | type Output = >::Align, Packed>>>::Output; 24 | } 25 | 26 | /// The amount of padding bytes needed to align an item at offset `Self` to 27 | /// `Align`. 28 | pub trait PadTo { 29 | type Output: Unsigned; 30 | } 31 | 32 | impl PadTo for Offset 33 | where 34 | Offset: RoundUpTo, 35 | >::Output: Sub, 36 | Diff<>::Output, Offset>: Unsigned, 37 | { 38 | type Output = Diff<>::Output, Offset>; 39 | } 40 | -------------------------------------------------------------------------------- /typic/src/private/layout/test.rs: -------------------------------------------------------------------------------- 1 | use super::Layout; 2 | use crate::private::bytelevel::{self as blvl, slot::*}; 3 | use crate::private::highlevel::{self as hlvl, MaxAlign, MinAlign, Type, Public}; 4 | use crate::private::num::*; 5 | use crate::typic; 6 | use static_assertions::*; 7 | 8 | const _: () = { 9 | #[typic::repr(C)] 10 | struct C; 11 | 12 | assert_type_eq_all!(::ReprAlign, MinAlign); 13 | assert_type_eq_all!(::ReprPacked, MaxAlign); 14 | assert_type_eq_all!(::HighLevel, hlvl::PNil); 15 | 16 | assert_type_eq_all!(>::Align, U1); 17 | assert_type_eq_all!(>::Size, U0); 18 | assert_type_eq_all!( 19 | >::ByteLevel, 20 | blvl::PCons, blvl::PNil> 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /typic/src/private/num.rs: -------------------------------------------------------------------------------- 1 | //! Type-level numbers. 2 | 3 | pub use core::ops::*; 4 | pub use typenum::{self, consts::*, operator_aliases::*, type_operators::*, uint::*, Unsigned}; 5 | 6 | pub trait SaturatingSub { 7 | type Output; 8 | } 9 | 10 | impl SaturatingSub for LHS 11 | where 12 | LHS: Min + core::ops::Sub>, 13 | { 14 | type Output = typenum::Diff>; 15 | } 16 | 17 | pub trait RoundUpTo { 18 | type Output: Unsigned; 19 | } 20 | 21 | impl RoundUpTo for N 22 | where 23 | N: Add, 24 | Sum: Sub, 25 | Sub1>: Rem, 26 | Sub1>: Sub>, Multiple>>, 27 | 28 | Diff>, Mod>, Multiple>>: Unsigned, 29 | { 30 | type Output = Diff>, Mod>, Multiple>>; 31 | } 32 | -------------------------------------------------------------------------------- /typic/src/private/stability.rs: -------------------------------------------------------------------------------- 1 | //! Traits for communicating layout guarantees. 2 | //! 3 | //! ```rust 4 | //! use typic::{self, stability::*}; 5 | //! 6 | //! #[typic::repr(C)] 7 | //! #[derive(StableABI)] 8 | //! struct Foo(u8, u16, u32); 9 | //! ``` 10 | 11 | //use crate::private::layout::{self, Layout}; 12 | use crate::layout::Layout; 13 | use crate::transmute::{self, neglect, TransmuteFrom, TransmuteInto}; 14 | use crate::private::highlevel::Public; 15 | 16 | /// Implements [`TransmutableInto`] and [`TransmutableFrom`] for a 17 | /// type, using that type as its own ABI bound. 18 | /// 19 | /// You must not make any changes to this type that narrows the 20 | /// visibility of its fields or changes its layout. 21 | pub use typic_derive::StableABI; 22 | 23 | /// Assert that `Self` is always transmutable into `Type`. 24 | pub unsafe trait TransmutableInto 25 | { 26 | type Type: Layout; 27 | } 28 | 29 | /// Assert that `Self` is always transmutable from `Type`. 30 | pub unsafe trait TransmutableFrom 31 | { 32 | type Type: Layout; 33 | } 34 | -------------------------------------------------------------------------------- /typic/src/private/target.rs: -------------------------------------------------------------------------------- 1 | //! Type-level information about the compilation target. 2 | 3 | use crate::private::num::*; 4 | 5 | /// The pointer width, in bytes, of the target platform. 6 | #[cfg(target_pointer_width = "8")] 7 | pub type PointerWidth = U1; 8 | #[cfg(target_pointer_width = "16")] 9 | pub type PointerWidth = U2; 10 | #[cfg(target_pointer_width = "32")] 11 | pub type PointerWidth = U4; 12 | #[cfg(target_pointer_width = "64")] 13 | pub type PointerWidth = U8; 14 | #[cfg(target_pointer_width = "128")] 15 | pub type PointerWidth = U16; 16 | -------------------------------------------------------------------------------- /typic/src/private/transmute.rs: -------------------------------------------------------------------------------- 1 | use core::mem; 2 | 3 | /// Allow bit-validity to expand. 4 | pub struct Variant; 5 | /// Constrain bit-validity to be equal. 6 | pub struct Invariant; 7 | 8 | /// Alignment of pointers is statically checked. 9 | pub struct Static; 10 | /// Alignment of pointers is unchecked. 11 | pub struct Unchecked; 12 | 13 | /// Transparency is enforced. 14 | pub struct Enforced; 15 | /// Transparency is not enforced. 16 | pub struct Unenforced; 17 | 18 | /// Validity is always enforced. 19 | pub struct AlwaysValid; 20 | /// Some invalidity is allowed. 21 | pub struct MaybeInvalid; 22 | 23 | pub mod neglect; 24 | 25 | #[rustfmt::skip] 26 | pub mod from_type; 27 | 28 | #[rustfmt::skip] 29 | pub mod from_layout; 30 | 31 | /// The source and destination types **must** have 32 | /// [stable ABIs][crate::stability::StableABI]. 33 | pub struct Stable; 34 | 35 | /// The source and destination types **may not** both have 36 | /// [stable ABIs][crate::stability::StableABI]. 37 | /// 38 | /// A transmutation between types with unstable ABIs is not necessarily 39 | /// unsafe, but the creators of the source and destination types do **not** 40 | /// guarantee that those types will have the same size, alignment, or 41 | /// data arrangement across minor releases. 42 | pub struct Unstable; 43 | 44 | /// A ***safe*** and ***sound*** value-to-value conversion. 45 | /// The reciprocal of [`TransmuteFrom`]. 46 | /// 47 | /// `TransmuteInto` is only implemented for `T` when 48 | /// 1. [`T` is ***soundly*** transmutable into `U`][soundness], and 49 | /// 2. [`T` is ***safely*** transmutable into `U`][safety]. 50 | /// 51 | /// See also [`safe_transmute`]. 52 | /// 53 | /// [`TransmuteFrom`]: TransmuteFrom 54 | /// [`safe_transmute`]: safe_transmute 55 | /// [soundness]: crate::transmute::unsafe_transmutation#when-is-a-transmutation-sound 56 | /// [safety]: crate::transmute::safe_transmutation 57 | pub unsafe trait TransmuteInto: UnsafeTransmuteInto 58 | where 59 | O: neglect::TransmuteOptions, 60 | { 61 | /// Reinterprets the bits of `self` as type `U`. 62 | fn transmute_into(self) -> U 63 | where 64 | Self: Sized; 65 | } 66 | 67 | unsafe impl TransmuteInto for T 68 | where 69 | U: TransmuteFrom, 70 | O: neglect::TransmuteOptions, 71 | Self: UnsafeTransmuteInto, 72 | { 73 | #[inline(always)] 74 | fn transmute_into(self) -> U { 75 | U::transmute_from(self) 76 | } 77 | } 78 | 79 | /// For ergonomics, until [rust-lang/rust#27336] is resolved. 80 | /// 81 | /// [rust-lang/rust#27336]: https://github.com/rust-lang/rust/issues/27336 82 | pub trait StableTransmuteInto: TransmuteInto { 83 | fn transmute_into(self) -> U; 84 | } 85 | 86 | impl StableTransmuteInto for T 87 | where 88 | T: TransmuteInto, 89 | { 90 | #[inline(always)] 91 | fn transmute_into(self) -> U 92 | { 93 | self.transmute_into() 94 | } 95 | } 96 | 97 | /// A ***safe*** and ***sound*** value-to-value conversion. 98 | /// The reciprocal of [`TransmuteInto`]. 99 | /// 100 | /// `TransmuteFrom` is only implemented for `U` when 101 | /// 1. [`T` is ***soundly*** transmutable into `U`][soundness], and 102 | /// 2. [`T` is ***safely*** transmutable into `U`][safety]. 103 | /// 104 | /// See also [`safe_transmute`]. 105 | /// 106 | /// [`TransmuteInto`]: TransmuteInto 107 | /// [`safe_transmute`]: safe_transmute 108 | /// [soundness]: crate::transmute::unsafe_transmutation#when-is-a-transmutation-sound 109 | /// [safety]: crate::transmute::safe_transmutation 110 | pub unsafe trait TransmuteFrom: Sized 111 | where 112 | O: neglect::TransmuteOptions, 113 | { 114 | /// Reinterprets the bits of `from` as type `Self`. 115 | fn transmute_from(from: T) -> Self; 116 | } 117 | 118 | unsafe impl TransmuteFrom for U 119 | where 120 | U: UnsafeTransmuteFrom, 121 | O: neglect::TransmuteOptions, 122 | { 123 | #[inline(always)] 124 | fn transmute_from(from: T) -> U { 125 | unsafe { U::unsafe_transmute_from(from) } 126 | } 127 | } 128 | 129 | /// A ***safe*** and ***sound*** value-to-value conversion. 130 | /// 131 | /// Consumes a value of type `T` and produces a value of type `U` by 132 | /// reinterpreting that value's bits. 133 | /// 134 | /// This will only convert `T` into `U` when: 135 | /// 1. [`T` is ***soundly*** transmutable into `U`][soundness], and 136 | /// 2. [`T` is ***safely*** transmutable into `U`][safety]. 137 | /// 138 | /// See also [`TransmuteInto`] and [`TransmuteFrom`]. 139 | /// 140 | /// [`TransmuteFrom`]: TransmuteFrom 141 | /// [`TransmuteInto`]: TransmuteInto 142 | /// [soundness]: crate::transmute::unsafe_transmutation#when-is-a-transmutation-sound 143 | /// [safety]: crate::transmute::safe_transmutation 144 | #[inline(always)] 145 | pub fn safe_transmute(from: T) -> U 146 | where 147 | U: from_type::FromType::Alignment, 150 | ::Transparency, 151 | ::Stability, 152 | ::Validity, 153 | >, 154 | O: neglect::TransmuteOptions, 155 | { 156 | unsafe { 157 | let to = mem::transmute_copy(&from); 158 | mem::forget(from); 159 | to 160 | } 161 | } 162 | 163 | /// A ***sound*** value-to-value conversion. 164 | /// The reciprocal of [`UnsafeTransmuteFrom`]. 165 | /// 166 | /// `UnsafeTransmuteInto` is only implemented for `T` when 167 | /// 1. [`T` is ***soundly*** transmutable into `U`][soundness]. 168 | /// 169 | /// See also [`unsafe_transmute`]. 170 | /// 171 | /// [`UnsafeTransmuteFrom`]: UnsafeTransmuteFrom 172 | /// [`unsafe_transmute`]: unsafe_transmute 173 | /// [soundness]: crate::transmute::unsafe_transmutation#when-is-a-transmutation-sound 174 | /// [safety]: crate::transmute::safe_transmutation 175 | pub unsafe trait UnsafeTransmuteInto: Sized 176 | where 177 | O: neglect::UnsafeTransmuteOptions, 178 | { 179 | /// Reinterprets the bits of `from` as type `Self`. 180 | unsafe fn unsafe_transmute_into(self) -> U; 181 | } 182 | 183 | unsafe impl UnsafeTransmuteInto for T 184 | where 185 | U: UnsafeTransmuteFrom, 186 | O: neglect::UnsafeTransmuteOptions, 187 | { 188 | #[inline(always)] 189 | unsafe fn unsafe_transmute_into(self) -> U { 190 | unsafe { U::unsafe_transmute_from(self) } 191 | } 192 | } 193 | 194 | /// A ***sound*** value-to-value conversion. 195 | /// The reciprocal of [`UnsafeTransmuteInto`]. 196 | /// 197 | /// `UnsafeTransmuteFrom` is only implemented for `U` when 198 | /// 1. [`T` is ***soundly*** transmutable into `U`][soundness]. 199 | /// 200 | /// See also [`unsafe_transmute`]. 201 | /// 202 | /// [`UnsafeTransmuteInto`]: crate::transmute::TransmuteInto 203 | /// [`unsafe_transmute`]: crate::transmute::unsafe_transmute 204 | /// [soundness]: crate::transmute::unsafe_transmutation#when-is-a-transmutation-sound 205 | /// [safety]: crate::transmute::safe_transmutation 206 | pub unsafe trait UnsafeTransmuteFrom: Sized 207 | where 208 | O: neglect::UnsafeTransmuteOptions, 209 | { 210 | /// Reinterprets the bits of `from` as type `Self`. 211 | unsafe fn unsafe_transmute_from(from: T) -> Self; 212 | } 213 | 214 | unsafe impl UnsafeTransmuteFrom for U 215 | where 216 | U: from_type::FromType::Alignment, 219 | ::Transparency, 220 | ::Stability, 221 | ::Validity, 222 | >, 223 | O: neglect::UnsafeTransmuteOptions, 224 | { 225 | #[inline(always)] 226 | unsafe fn unsafe_transmute_from(from: T) -> U { 227 | unsafe { unsafe_transmute::(from) } 228 | } 229 | } 230 | 231 | /// A ***sound*** value-to-value conversion. 232 | /// 233 | /// Consumes a value of type `T` and produces a value of type `U` by 234 | /// reinterpreting that value's bits. 235 | /// 236 | /// This will only convert `T` into `U` when: 237 | /// 1. [`T` is ***soundly*** transmutable into `U`][soundness]. 238 | /// 239 | /// It is **unsafe**, because `U` may be a user-defined type that enforces 240 | /// additional validity restrictions in its constructor(s). This function 241 | /// bypasses those restrictions, and may lead to later unsoundness. 242 | /// 243 | /// [soundness]: crate::transmute::unsafe_transmutation#when-is-a-transmutation-sound 244 | /// [safety]: crate::transmute::safe_transmutation 245 | #[inline(always)] 246 | pub unsafe fn unsafe_transmute(from: T) -> U 247 | where 248 | U: from_type::FromType::Alignment, 251 | ::Transparency, 252 | ::Stability, 253 | ::Validity>, 254 | O: neglect::UnsafeTransmuteOptions, 255 | { 256 | let to = mem::transmute_copy(&from); 257 | mem::forget(from); 258 | to 259 | } 260 | -------------------------------------------------------------------------------- /typic/src/private/transmute/from_layout.rs: -------------------------------------------------------------------------------- 1 | use crate::private::bytelevel::{ 2 | self as blv, 3 | slot::{Pub, Priv}, 4 | slot::{bytes::kind, *}, 5 | PCons, PNil, ReferenceBytes, 6 | }; 7 | use crate::private::layout::{Layout, AlignedTo}; 8 | use crate::private::num::{self, UInt, UTerm}; 9 | use super::from_type::FromType; 10 | use super::{Variant, Invariant, Static, Unchecked, Enforced, Unenforced, Stable, Unstable, AlwaysValid, MaybeInvalid}; 11 | use crate::stability::*; 12 | mod consume; 13 | pub use consume::Consume; 14 | 15 | mod flatten; 16 | pub use flatten::Flatten; 17 | 18 | /// A marker trait implemented if the layout `T` is compatible with the layout 19 | /// `Self`. 20 | pub unsafe trait FromLayout< 21 | SourceLayout, 22 | Options, 23 | > {} 24 | 25 | /// ANYTHING -> [] 26 | unsafe impl< 27 | SourceLayout, 28 | Options 29 | > 30 | FromLayout< 31 | SourceLayout, 32 | Options 33 | > for PNil {} 34 | 35 | #[rustfmt::skip] unsafe impl< 36 | UVis, UKind, URest, 37 | Options, 38 | > 39 | FromLayout for PCons, URest> 42 | where 43 | URest: FromLayout, 44 | {} 45 | 46 | #[rustfmt::skip] unsafe impl< 47 | UVis, U, URest, 48 | Options, 49 | > FromLayout 50 | for PCons, URest> 51 | where 52 | URest: FromLayout, 53 | {} 54 | 55 | 56 | /// ```rust 57 | /// use typic::private::transmute::{Stable, Variant, Static, Enforced, AlwaysValid, from_layout::FromLayout}; 58 | /// use typic::private::bytelevel::{PCons, PNil, slot::{InitializedSlot, Pub, Priv}}; 59 | /// use typic::private::num::U1; 60 | /// fn can_transmute, Variance, Transparency>() {} 61 | /// 62 | /// can_transmute::< 63 | /// PCons, PNil>, 64 | /// PCons, PNil>, 65 | /// Variant, Enforced>(); 66 | /// 67 | /// can_transmute::< 68 | /// PCons, PNil>, 69 | /// PCons, PNil>, 70 | /// Variant, Enforced>(); 71 | /// ``` 72 | mod bytes_to { 73 | use super::*; 74 | 75 | /// [Bytes|_] -> [Array|_] 76 | #[rustfmt::skip] unsafe impl 79 | FromLayout, TRest>, Options> 80 | for PCons, URest> 81 | where 82 | Self: Flatten, 83 | ::Output: 84 | FromLayout, TRest>, Options> 85 | {} 86 | 87 | /// [Bytes|_] -> [Bytes|_] 88 | #[rustfmt::skip] unsafe impl 90 | FromLayout, TRest>, (Variance, Alignment, Transparency, Stability, Validity)> 91 | for PCons, URest> 92 | where 93 | Bytes: BytesFromBytes, Variance, Transparency, Validity>, 94 | USize: Consume, 95 | 96 | Bytes>::TSize>: blv::Add, 97 | Bytes>::USize>: blv::Add, 98 | 99 | blv::Sum>::USize>, URest>: 100 | FromLayout>::TSize>, TRest>, (Variance, Alignment, Transparency, Stability, Validity)> 101 | {} 102 | 103 | /// Implemented if a byte of `TKind` is transmutable to a byte of `Self`. 104 | pub trait BytesFromBytes {} 105 | 106 | macro_rules! constrain { 107 | ($($TKind: path => $UKind: path,)*) => { 108 | $( 109 | /// Regardless of variance and transparency, this `pub` to `pub` conversion is safe. 110 | impl 111 | BytesFromBytes, Variance, Transparency, Validity> 112 | for Bytes 113 | {} 114 | 115 | /// A `priv` to `pub` conversion is safe only if the transmutation is variant. 116 | impl 117 | BytesFromBytes, Variant, Transparency, Validity> 118 | for Bytes 119 | {} 120 | 121 | /// A `priv`/`pub` to `priv` conversion is only safe if transparency is unchecked. 122 | impl 123 | BytesFromBytes, Variance, Unenforced, Validity> 124 | for Bytes 125 | {} 126 | )* 127 | }; 128 | } 129 | 130 | constrain![ 131 | kind::NonZero => kind::NonZero , 132 | kind::Initialized => kind::Initialized , 133 | kind::Uninitialized => kind::Uninitialized , 134 | ]; 135 | 136 | macro_rules! relax { 137 | ($($TKind: path => $UKind: path,)*) => { 138 | $( 139 | /// Regardless of variance and transparency, this `pub` to `pub` conversion is safe. 140 | impl 141 | BytesFromBytes, Variant, Transparency, Validity> 142 | for Bytes 143 | {} 144 | 145 | /// A `priv` to `pub` conversion is safe only if the transmutation is variant. 146 | impl 147 | BytesFromBytes, Variant, Transparency, Validity> 148 | for Bytes 149 | {} 150 | 151 | /// A `priv`/`pub` to `priv` conversion is only safe if transparency is unchecked. 152 | impl 153 | BytesFromBytes, Variant, Unenforced, Validity> 154 | for Bytes 155 | {} 156 | )* 157 | }; 158 | } 159 | 160 | relax![ 161 | kind::NonZero => kind::Uninitialized , 162 | kind::NonZero => kind::Initialized , 163 | kind::Initialized => kind::Uninitialized , 164 | ]; 165 | 166 | // If either sizes are empty, `BytesFromBytes` vacuously holds. 167 | // this is sketchy, but I think it's alright because of how 168 | // BytesFromBytes is used alongside `Consume`. Unfortunately, 169 | // it's been months since I last touched this code. 170 | // todo: refactor all of this. 171 | impl 172 | BytesFromBytes, Variance, Transparency, Validity> 173 | for Bytes> {} 174 | 175 | // todo: wtf. why did I write this? 176 | // /// [Bytes|_] -> [Reference|_] 177 | // #[rustfmt::skip] unsafe impl<'u, TVis, TKind, TRest, UVis, UK, U, URest, Options> 178 | // FromLayout, TRest>, Options> 179 | // for PCons, URest> 180 | // where 181 | // Self: FromLayout, 182 | // {} 183 | } 184 | 185 | mod array_to { 186 | use super::*; 187 | 188 | /// [Array|_] -> [Array|_] 189 | #[rustfmt::skip] unsafe impl 190 | FromLayout, TRest>, Options> 191 | for PCons, URest> 192 | where 193 | PCons, TRest>: Flatten, 194 | PCons, URest>: Flatten, 195 | 196 | , URest> as Flatten>::Output: 197 | FromLayout<, TRest> as Flatten>::Output, Options>, 198 | {} 199 | 200 | /// [Array|_] -> [Bytes|_] 201 | #[rustfmt::skip] unsafe impl 202 | FromLayout, TRest>, Options> 203 | for PCons, URest> 204 | where 205 | PCons, TRest>: Flatten, 206 | 207 | Self: FromLayout<, TRest> as Flatten>::Output, Options>, 208 | {} 209 | 210 | /// [Array|_] -> [Reference|_] 211 | #[rustfmt::skip] unsafe impl<'u, TVis, T, TSize, TRest, UK, UVis, U, URest, Options> 212 | FromLayout, TRest>, Options> 213 | for PCons, URest> 214 | where 215 | PCons, TRest>: Flatten, 216 | 217 | Self: FromLayout<, TRest> as Flatten>::Output, Options>, 218 | {} 219 | } 220 | 221 | mod reference_to { 222 | use super::*; 223 | 224 | /// [Reference|_] -> [Array|_] 225 | #[rustfmt::skip] unsafe impl<'t, TVis, T, TK, TRest, UVis, U, USize, URest, Options> 226 | FromLayout, TRest>, Options> 227 | for PCons, URest> 228 | where 229 | Self: Flatten, 230 | ::Output: 231 | FromLayout, TRest>, Options>, 232 | {} 233 | 234 | /// [Reference|_] -> [Bytes|_] 235 | #[rustfmt::skip] unsafe impl<'t, TVis, T, TK, TRest, UVis, UKind, USize, URest, Options> 236 | FromLayout, TRest>, Options> 237 | for PCons, URest> 238 | where 239 | Self: FromLayout, Options>, 240 | {} 241 | 242 | pub trait FromMutability {} 243 | impl FromMutability for Unique {} 244 | impl FromMutability for Shared {} 245 | impl FromMutability for Shared {} 246 | 247 | pub trait FromAlignment {} 248 | 249 | impl FromAlignment for U 250 | where 251 | U: TransmutableInto, 252 | T: TransmutableFrom, 253 | {} 254 | 255 | impl FromAlignment for U {} 256 | 257 | /// [Reference|_] -> [Reference|_] 258 | #[rustfmt::skip] unsafe impl<'t, 'u, TVis, T, TK, TRest, UVis, U, UK, URest, Variance, Transparency, Stability, Validity> 259 | FromLayout, TRest>, (Variance, Unchecked, Transparency, Stability, Validity)> 260 | for PCons, URest> 261 | where 262 | 't: 'u, 263 | UK: FromMutability, 264 | U: FromType, 265 | {} 266 | 267 | /// `[Reference|_] -> [Reference|_]` 268 | /// ```rust 269 | /// use typic::private::transmute::{Stable, Variant, Static, Enforced, AlwaysValid, from_layout::FromLayout}; 270 | /// use typic::private::bytelevel::{PCons, PNil, slot::{Pub, Priv, SharedRef}}; 271 | /// fn can_transmute>() {} 272 | /// 273 | /// type T = SharedRef<'static, Pub, ()>; 274 | /// can_transmute::, PCons>(); 275 | /// ``` 276 | #[rustfmt::skip] unsafe impl<'t, 'u, TVis, T, TK, TRest, UVis, U, UK, URest, Variance, Transparency, Stability, Validity> 277 | FromLayout, TRest>, (Variance, Static, Transparency, Stability, Validity)> 278 | for PCons, URest> 279 | where 280 | 't: 'u, 281 | UK: FromMutability, 282 | U: FromAlignment + AlignedTo + FromType, 283 | {} 284 | } 285 | 286 | 287 | #[cfg(test)] 288 | mod test { 289 | use super::*; 290 | 291 | fn subsumes>() 292 | {} 293 | 294 | macro_rules! P { 295 | () => { crate::private::bytelevel::PNil }; 296 | (...$Rest:ty) => { $Rest }; 297 | ($A:ty) => { P![$A,] }; 298 | ($A:ty, $($tok:tt)*) => { 299 | crate::private::bytelevel::PCons<$A, P![$($tok)*]> 300 | }; 301 | } 302 | 303 | #[test] 304 | fn test() { 305 | use crate::private::{self, num::*, highlevel::Type, layout::Layout}; 306 | use crate::private::bytelevel::slot::{bytes::kind, *}; 307 | use static_assertions::*; 308 | use crate::private::bytelevel as blvl; 309 | 310 | subsumes::< 311 | P![PaddingSlot], 312 | P![] 313 | >(); 314 | 315 | subsumes::< 316 | P![PaddingSlot], 317 | P![PaddingSlot] 318 | >(); 319 | 320 | subsumes::< 321 | P![PaddingSlot, PaddingSlot], 322 | P![PaddingSlot] 323 | >(); 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /typic/src/private/transmute/from_layout/consume.rs: -------------------------------------------------------------------------------- 1 | use crate::private::num; 2 | 3 | /// Consume `Maximum` of the leading bytes of two layouts. 4 | pub trait Consume { 5 | /// The number of bytes to append back on `TRest`. 6 | type TSize; 7 | 8 | /// The number of bytes to append back on `URest`. 9 | type USize; 10 | } 11 | 12 | 13 | #[rustfmt::skip] 14 | impl Consume for USize 15 | where 16 | TSize: num::Min, 17 | TSize: num::Sub>, 18 | USize: num::Sub>, 19 | { 20 | type TSize = num::Diff>; 21 | type USize = num::Diff>; 22 | } -------------------------------------------------------------------------------- /typic/src/private/transmute/from_layout/flatten.rs: -------------------------------------------------------------------------------- 1 | use crate::private::num; 2 | 3 | use crate::private::layout::Layout; 4 | use crate::private::bytelevel::{self as blv, slot::Array, PCons}; 5 | 6 | pub trait Flatten { 7 | type Output; 8 | } 9 | 10 | impl Flatten for PCons, TRest> 11 | where 12 | { 13 | type Output = TRest; 14 | } 15 | 16 | impl Flatten for PCons>, TRest> 17 | where 18 | T: Layout, 19 | num::UInt: num::Sub, 20 | 21 | >::ByteLevel: 22 | blv::Add>>, TRest>>, 23 | { 24 | type Output = 25 | blv::Sum< 26 | >::ByteLevel, 27 | PCons>>, TRest> 28 | >; 29 | } -------------------------------------------------------------------------------- /typic/src/private/transmute/from_type.rs: -------------------------------------------------------------------------------- 1 | use crate::stability::*; 2 | use crate::private::layout::Layout; 3 | use crate::internal::{Public, Private}; 4 | use super::{Stable, Unstable, from_layout::FromLayout}; 5 | 6 | /// A marker trait implemented if every instance of `T` is transmutable into 7 | /// an instance of `Self`. 8 | pub unsafe trait FromType< 9 | SourceType, 10 | // Can bit-validity be widened? 11 | Variance, 12 | // Is alignment checked? 13 | Alignment, 14 | // Is library safety checked? 15 | Transparency, 16 | /// Must the source and destination types have stable representations? 17 | Stability, 18 | /// Must all values of the source type be a valid instance of the destination type? 19 | Validity, 20 | >{} 21 | 22 | unsafe impl 23 | FromType for U 24 | where 25 | T: Layout, 26 | U: Layout, 27 | >::ByteLevel: FromLayout<>::ByteLevel, 28 | (Variance, 29 | Alignment, 30 | Transparency, 31 | Unstable, 32 | Validity,)> 33 | {} 34 | 35 | unsafe impl 36 | FromType for U 37 | where 38 | T: TransmutableFrom + Layout, 39 | U: TransmutableInto + Layout, 40 | 41 | // If stability is being enforced, then 42 | // the widest extent of the source type 43 | // must be transmutable into the narrowest 44 | // extent of the destination type. 45 | ::Type: 46 | FromType<::Type, 47 | Variance, 48 | Alignment, 49 | Transparency, 50 | Unstable, 51 | Validity>, 52 | 53 | >::ByteLevel: FromLayout<>::ByteLevel, 54 | (Variance, 55 | Alignment, 56 | Transparency, 57 | Stable, 58 | Validity,)> 59 | {} -------------------------------------------------------------------------------- /typic/src/private/transmute/neglect.rs: -------------------------------------------------------------------------------- 1 | /// Neglect statically guaranteeing pointer alignments. 2 | /// 3 | /// By default, Typic ***statically requires*** that, when transmuting 4 | /// between references, the destination type does not have stronger 5 | /// alignment requirements than the source type. 6 | /// 7 | /// This option is useful for implementing common fallible 8 | /// transmutations, [like bytemuck's `try_cast_ref`](crate::extras::bytemuck::try_cast_ref). 9 | /// 10 | /// This option is ***only*** available for ***unsafe*** transmutations, 11 | /// since dereferencing an unaligned pointer may invoke UB. 12 | pub struct Alignment; 13 | 14 | /// Neglect statically guaranteeing that corresponding bytes in the source and destination 15 | /// types have appropriate visibility. 16 | /// 17 | /// Typic assumes that if a field of a type isn't `pub`, the type might 18 | /// enforce invariants on its value. By default, Typic ***statically 19 | /// requires*** that all bytes in the destination type are marked `pub`. 20 | /// 21 | /// If you have special knowledge about the type (e.g., because you're 22 | /// the author), you can opt-out of this guarantee by asserting 23 | /// `T: UnsafeTransmuteInto`. 24 | /// 25 | /// This option is ***only*** available for ***unsafe*** transmutations, 26 | /// since calling methods on the transmuted reference may only be safe if 27 | /// the type's internal invariants are upheld. 28 | pub struct Transparency; 29 | 30 | /// Neglect statically guaranteeing that the source and destination types have stable 31 | /// in-memory representations. 32 | /// 33 | /// By default, Typic ***statically requires*** that the layouts of the 34 | /// source and destination types are part of their API guarantee. Library 35 | /// authors indicate this for their types by implementing a marker trait. 36 | /// This trait should only be implementable for types where Rust makes 37 | /// guarantees about their layout (e.g., `#[repr(C)]`). 38 | /// 39 | /// This is the only option available for safe transmutations. 40 | /// 41 | /// Typic will ***still*** reject transmutes between types where the 42 | /// layouts of the source or destination types are compiler UB (e.g., 43 | /// most `repr(Rust)` types). 44 | pub struct Stability; 45 | 46 | /// Neglect statically guaranteeing that all instances of the source type are bit-valid 47 | /// instances of the destination type. 48 | /// 49 | /// (Typic does not currently fully implement this, but will soon.) 50 | /// 51 | /// By default, Typic only accepts transmutations for which all possible 52 | /// values of the source type are bit-valid values of the destination 53 | /// type. (This means no `u8 → bool` transmutes!) 54 | /// 55 | /// If you have special knowledge about the value (e.g., because you've 56 | /// ensured at runtime that it's a bit-valid instance of the destination 57 | /// type), you can opt-out of this guarantee by asserting 58 | /// `T: UnsafeTransmuteInto`. 59 | /// 60 | /// Typic will still reject transmutations that cannot possibly be valid 61 | /// for any value, e.g.: 62 | /// ```ignore 63 | /// #[typic::repr(C)] enum Foo { N = 24 } 64 | /// #[typic::repr(C)] enum Bar { N = 24 } 65 | /// 66 | /// let bar : Bar = (Foo::N).unsafe_transmute_into() // Compile error! 67 | /// ``` 68 | pub struct Validity; 69 | 70 | /// Options for safe and unsafe transmutation. 71 | pub trait TransmuteOptions: UnsafeTransmuteOptions { 72 | type Stability; 73 | } 74 | 75 | impl TransmuteOptions for () { 76 | type Stability = super::Stable; 77 | } 78 | 79 | impl TransmuteOptions for Stability { 80 | type Stability = super::Unstable; 81 | } 82 | 83 | impl UnsafeTransmuteOptions for O 84 | where 85 | O: TransmuteOptions 86 | { 87 | type Alignment = super::Static; 88 | type Transparency = super::Enforced; 89 | type Stability = ::Stability; 90 | type Validity = super::AlwaysValid; 91 | } 92 | 93 | /// Options for unsafe transmutation. 94 | pub trait UnsafeTransmuteOptions { 95 | type Alignment; 96 | type Transparency; 97 | type Stability; 98 | type Validity; 99 | } 100 | 101 | impl UnsafeTransmuteOptions for Alignment { 102 | type Alignment = super::Unchecked; 103 | type Stability = super::Stable; 104 | type Transparency = super::Enforced; 105 | type Validity = super::AlwaysValid; 106 | } 107 | 108 | impl UnsafeTransmuteOptions for (Alignment,) { 109 | type Alignment = super::Unchecked; 110 | type Stability = super::Stable; 111 | type Transparency = super::Enforced; 112 | type Validity = super::AlwaysValid; 113 | } 114 | 115 | impl UnsafeTransmuteOptions for Transparency { 116 | type Alignment = super::Static; 117 | type Stability = super::Stable; 118 | type Transparency = super::Unenforced; 119 | type Validity = super::AlwaysValid; 120 | } 121 | 122 | impl UnsafeTransmuteOptions for (Transparency,) { 123 | type Alignment = super::Static; 124 | type Stability = super::Stable; 125 | type Transparency = super::Unenforced; 126 | type Validity = super::AlwaysValid; 127 | } 128 | 129 | impl UnsafeTransmuteOptions for Validity { 130 | type Alignment = super::Static; 131 | type Stability = super::Stable; 132 | type Transparency = super::Unenforced; 133 | type Validity = super::AlwaysValid; 134 | } 135 | 136 | impl UnsafeTransmuteOptions for (Validity,) { 137 | type Alignment = super::Static; 138 | type Stability = super::Stable; 139 | type Transparency = super::Enforced; 140 | type Validity = super::MaybeInvalid; 141 | } 142 | 143 | impl UnsafeTransmuteOptions for (Alignment, Transparency) { 144 | type Alignment = ::Alignment; 145 | type Stability = ::Stability; 146 | type Transparency = ::Transparency; 147 | type Validity = ::Validity; 148 | } 149 | 150 | impl UnsafeTransmuteOptions for (Alignment, Stability) { 151 | type Alignment = ::Alignment; 152 | type Stability = ::Stability; 153 | type Transparency = ::Transparency; 154 | type Validity = ::Validity; 155 | } 156 | 157 | impl UnsafeTransmuteOptions for (Alignment, Validity) { 158 | type Alignment = ::Alignment; 159 | type Stability = ::Stability; 160 | type Transparency = ::Transparency; 161 | type Validity = ::Validity; 162 | } 163 | 164 | impl UnsafeTransmuteOptions for (Transparency, Stability) { 165 | type Alignment = ::Alignment; 166 | type Stability = ::Stability; 167 | type Transparency = ::Transparency; 168 | type Validity = ::Validity; 169 | } 170 | 171 | impl UnsafeTransmuteOptions for (Transparency, Validity) { 172 | type Alignment = ::Alignment; 173 | type Stability = ::Stability; 174 | type Transparency = ::Transparency; 175 | type Validity = ::Validity; 176 | } 177 | 178 | impl UnsafeTransmuteOptions for (Stability, Validity) { 179 | type Alignment = ::Alignment; 180 | type Stability = ::Stability; 181 | type Transparency = ::Transparency; 182 | type Validity = ::Validity; 183 | } 184 | 185 | impl UnsafeTransmuteOptions for (Alignment, Transparency, Stability) { 186 | type Alignment = ::Alignment; 187 | type Stability = ::Stability; 188 | type Transparency = ::Transparency; 189 | type Validity = ::Validity; 190 | } 191 | 192 | impl UnsafeTransmuteOptions for (Alignment, Transparency, Validity) { 193 | type Alignment = ::Alignment; 194 | type Stability = ::Stability; 195 | type Transparency = ::Transparency; 196 | type Validity = ::Validity; 197 | } 198 | 199 | impl UnsafeTransmuteOptions for (Alignment, Stability, Validity) { 200 | type Alignment = ::Alignment; 201 | type Stability = ::Stability; 202 | type Transparency = ::Transparency; 203 | type Validity = ::Validity; 204 | } 205 | 206 | impl UnsafeTransmuteOptions for (Transparency, Stability, Validity) { 207 | type Alignment = ::Alignment; 208 | type Stability = ::Stability; 209 | type Transparency = ::Transparency; 210 | type Validity = ::Validity; 211 | } 212 | 213 | 214 | impl UnsafeTransmuteOptions for (Alignment, Transparency, Stability, Validity) { 215 | type Alignment = ::Alignment; 216 | type Stability = ::Stability; 217 | type Transparency = ::Transparency; 218 | type Validity = ::Validity; 219 | } -------------------------------------------------------------------------------- /typic/src/transmute.rs: -------------------------------------------------------------------------------- 1 | //! Traits for safe and sound transmutation. 2 | //! 3 | //! [soundness]: crate::transmute::unsafe_transmutation#when-is-a-transmutation-sound 4 | //! [safety]: crate::transmute::safe_transmutation 5 | //! 6 | //! ## Three Types of Transmutation 7 | //! 8 | //! ### Unsound Transmutation 9 | //! [`transmute`]: core::mem::transmute 10 | //! [`transmute_copy`]: core::mem::transmute_copy 11 | //! 12 | //! The [`transmute`] and [`transmute_copy`] intrinsics 13 | //! allow for the ***unsafe*** and ***unsound*** transmutation between any `T` 14 | //! and `U`. 15 | //! 16 | //! These intrinsics are deeply unsafe. The Rust compiler will accept uses of 17 | //! these intrinsics even when `T` and `U` do not have well-defined layouts. 18 | //! ***Always use a [safe transmutation](#safe-transmutation) method instead, 19 | //! if possible.*** If you are unable to use a safe transmutation method, 20 | //! ***you may be relying on undefined compiler behavior***. 21 | //! 22 | //! ### Sound Transmutation 23 | //! [`unsafe_transmute`]: self::unsafe_transmute 24 | //! 25 | //! The [`unsafe_transmute`] function allows for the ***unsafe*** transmutation 26 | //! between `T` and `U`, when merely transmuting from `T` to `U` will not cause 27 | //! undefined behavior. For the key rules that govern when `T` is soundly 28 | //! convertible to `U`, see ***[When is a transmutation sound?][soundness]***. 29 | //! 30 | //! This operation is `unsafe`, as it will bypass any user-defined validity 31 | //! restrictions that `U` places on its fields and enforces with its 32 | //! constructors and methods. 33 | //! 34 | //! ***Always use a [safe transmutation](#safe-transmutation) method instead, if 35 | //! possible.*** If you are unable to use a safe transmutation method, you may 36 | //! be violating library invariants. 37 | //! 38 | //! ### Safe Transmutation 39 | //! [safe transmutation]: #safe-transmutation 40 | //! [`TransmuteInto`]: self::TransmuteInto 41 | //! 42 | //! The [`TransmuteInto`] trait is implemented for a type `T` if: 43 | //! 1. [`T` is ***soundly*** transmutable into `U`][soundness], and 44 | //! 2. [`T` is ***safely*** transmutable into `U`][safety]. 45 | //! 46 | //! If you are unable to use [`TransmuteInto`], you may be attempting a 47 | //! transmutation that is relying unspecified behavior. 48 | 49 | pub mod safe_transmutation; 50 | pub mod unsafe_transmutation; 51 | 52 | #[doc(inline)] 53 | pub use crate::private::transmute::{ 54 | safe_transmute, 55 | StableTransmuteInto, 56 | TransmuteFrom, 57 | TransmuteInto, 58 | neglect::TransmuteOptions, 59 | 60 | unsafe_transmute, 61 | UnsafeTransmuteFrom, 62 | UnsafeTransmuteInto, 63 | neglect::UnsafeTransmuteOptions, 64 | }; 65 | 66 | /// What static checks should Typic neglect? 67 | pub mod neglect { 68 | #[doc(inline)] 69 | pub use crate::private::transmute::neglect::{ 70 | Alignment, 71 | Stability, 72 | Transparency, 73 | Validity, 74 | }; 75 | } 76 | -------------------------------------------------------------------------------- /typic/src/transmute/safe_transmutation.rs: -------------------------------------------------------------------------------- 1 | //! Guidance and tools for ***safe*** transmutation. 2 | //! 3 | //! A [sound transmutation] is safe only if the resulting value cannot possibly 4 | //! violate library-enforced invariants. Typic assumes that all non-zero-sized 5 | //! fields with any visibility besides `pub` could have library-enforced 6 | //! invariants. 7 | //! 8 | //! [sound transmutation]: crate#sound-transmutation 9 | //! [soundness]: crate::sound#when-is-a-transmutation-sound 10 | //! [`TransmuteInto`]: crate::TransmuteInto 11 | //! [`unsafe_transmute`]: crate::unsafe_transmute 12 | //! 13 | //! ## Why is safety different than soundness? 14 | //! Consider the type `Constrained`, which enforces a validity constraint on its 15 | //! fields, and the type `Unconstrained` (which has no internal validity 16 | //! constraints): 17 | //! 18 | //! ``` 19 | //! # use typic::docs::prelude::*; 20 | //! #[typic::repr(C)] 21 | //! #[derive(StableABI)] 22 | //! pub struct Constrained { 23 | //! wizz: i8, 24 | //! bang: u8, 25 | //! } 26 | //! 27 | //! impl Constrained { 28 | //! /// the sum of `wizz` and `bang` must be greater than or equal to zero. 29 | //! pub fn new(wizz: i8, bang: u8) -> Self { 30 | //! assert!((wizz as i16) / (bang as i16) >= 0); 31 | //! Constrained { wizz, bang } 32 | //! } 33 | //! 34 | //! pub fn something_dangerous(&self) { 35 | //! unsafe { 36 | //! // do something that's only safe if `wizz + bang >= 0` 37 | //! } 38 | //! } 39 | //! } 40 | //! 41 | //! #[typic::repr(C)] 42 | //! #[derive(StableABI)] 43 | //! pub struct Unconstrained { 44 | //! pub wizz: u8, 45 | //! pub bang: i8, 46 | //! } 47 | //! ``` 48 | //! 49 | //! It is [sound][soundness] to transmute an instance of `Unconstrained` into 50 | //! `Constrained`: 51 | //! ``` 52 | //! use typic::docs::prelude::*; 53 | //! use typic::transmute::neglect; 54 | //! let _ : Constrained = unsafe { unsafe_transmute::<_, _, neglect::Transparency>(Unconstrained::default()) }; 55 | //! ``` 56 | //! ...but it is **not** safe! The [`unsafe_transmute`] function creates an 57 | //! instance of `Bar` _without_ calling its `new` constructor, thereby bypassing 58 | //! the safety check which ensures `something_dangerous` does not violate Rust's 59 | //! memory model. The compiler will reject our program if we try to safely 60 | //! transmute `Unconstrained` to `Constrained`: 61 | //! ```compile_fail 62 | //! # use typic::docs::prelude::*; 63 | //! let unconstrained = Unconstrained::default(); 64 | //! let _ : Constrained = unconstrained.transmute_into(); 65 | //! ``` 66 | //! 67 | //! Or, ***automatically***, by marking the fields `pub`: 68 | //! ``` 69 | //! # use typic::docs::prelude::*; 70 | //! #[typic::repr(C)] 71 | //! #[derive(StableABI)] 72 | //! pub struct Unconstrained { 73 | //! pub wizz: u8, 74 | //! pub bang: i8, 75 | //! } 76 | //! 77 | //! let _ : Unconstrained = u16::default().transmute_into(); 78 | //! ``` 79 | //! 80 | //! If the fields are marked `pub`, the type cannot possibly rely on any 81 | //! internal validity requirements, as users of the type are free to manipulate 82 | //! its fields direclty via the `.` operator. 83 | //! 84 | //! This rule applies to private fields that are zero-sized. It is 85 | //! safe to transmute from `Bar` to `Foo`, because `Foo`'s constructor 86 | //! is `pub`: 87 | //! ```rust 88 | //! # use typic::docs::prelude::*; 89 | //! #[typic::repr(C)] 90 | //! #[derive(StableABI)] 91 | //! struct ZST; 92 | //! 93 | //! #[typic::repr(C)] 94 | //! #[derive(StableABI)] 95 | //! struct Foo(pub ZST); 96 | //! 97 | //! #[typic::repr(C)] 98 | //! #[derive(StableABI)] 99 | //! struct Bar(ZST); 100 | //! 101 | //! let _ : Foo = Bar(ZST).transmute_into(); 102 | //! ``` 103 | //! It is *not* safe to transmute from `Foo` to `Bar`, because `Bar`'s 104 | //! constructor is not public: 105 | //! ```compile_fail 106 | //! # use typic::docs::prelude::*; 107 | //! # #[typic::repr(C)] 108 | //! # #[derive(StableABI)] 109 | //! # struct ZST; 110 | //! # 111 | //! # #[typic::repr(C)] 112 | //! # #[derive(StableABI)] 113 | //! # struct Foo(pub ZST); 114 | //! # 115 | //! # #[typic::repr(C)] 116 | //! # #[derive(StableABI)] 117 | //! # struct Bar(ZST); 118 | //! let _ : Bar = Foo(ZST).transmute_into(); 119 | //! ``` 120 | //! ## Safely transmuting references 121 | //! When safely transmuting owned values, all non-padding bytes in the source 122 | //! type must correspond to `pub` bytes in the destination type: 123 | //! ``` 124 | //! # use typic::docs::prelude::*; 125 | //! let _ : Unconstrained = Constrained::default().transmute_into(); 126 | //! ``` 127 | //! The visibility (or lack thereof) of bytes in the source type does not 128 | //! affect safety. 129 | //! 130 | //! When safely transmuting references, each corresponding byte in the source 131 | //! and destination types must have the _same_ visibility. Without this 132 | //! restriction, you could inadvertently violate library invariants of a type 133 | //! by transmuting and mutating a mutable reference to it: 134 | //! 135 | //! ```compile_fail 136 | //! # use typic::docs::prelude::*; 137 | //! let mut x = Constrained::default(); 138 | //! 139 | //! { 140 | //! let y : &mut Unconstrained = (&mut x).transmute_into(); 141 | //! // ^^^^^^^^^^^^^^ 142 | //! // Compile Error! 143 | //! let z : u8 = -100i8.transmute_into(); 144 | //! y.wizz = z; 145 | //! } 146 | //! 147 | //! // Ack! `x.wizz + x.bang` is now -100! 148 | //! // This violates the safety invariant of `something_dangerous`! 149 | //! x.something_dangerous(); 150 | //! ``` 151 | 152 | pub use super::{ 153 | safe_transmute, 154 | TransmuteFrom, 155 | TransmuteInto, 156 | StableTransmuteInto, 157 | TransmuteOptions 158 | }; 159 | 160 | /// Configuration options for ***safe*** transmutations. 161 | pub mod neglect { 162 | pub use crate::transmute::neglect::Stability; 163 | } 164 | -------------------------------------------------------------------------------- /typic/src/transmute/unsafe_transmutation.rs: -------------------------------------------------------------------------------- 1 | //! Guidance and tools for ***sound*** transmutation. 2 | //! 3 | //! A transmutation is ***sound*** if the mere act of transmutation is 4 | //! guaranteed to not violate Rust's memory model. 5 | //! 6 | //! [`unsafe_transmute`]: crate::unsafe_transmute 7 | //! [`TransmuteInto`]: crate::TransmuteInto 8 | //! 9 | //! ## When is a transmutation sound? 10 | //! [`NonZeroU8`]: core::num::NonZeroU8 11 | //! 12 | //! A transmutation is only sound if it occurs between types with [well-defined 13 | //! representations](#well-defined-representation), and does not violate Rust's 14 | //! memory model. See [*Transmutations Between Owned Values*][transmute-owned], 15 | //! and [*Transmutations Between References*][transmute-references]. These rules 16 | //! are automatically enforced by [`unsafe_transmute`] and [`TransmuteInto`]. 17 | //! 18 | //! ### Well-Defined Representation 19 | //! [`u8`]: core::u8 20 | //! [`f32`]: core::f32 21 | //! 22 | //! Transmutation is ***always unsound*** if it occurs between types with 23 | //! unspecified representations. Most of Rust's primitive types have specified 24 | //! representations. That is, the layout characteristics of [`u8`], [`f32`] and 25 | //! others are guaranteed to be stable across compiler versions. 26 | //! 27 | //! In contrast, most `struct` and `enum` types defined without an explicit 28 | //! `#[repr(C)]` or `#[repr(transparent)]` attribute do ***not*** have 29 | //! well-specified layout characteristics. 30 | //! 31 | //! To ensure that types you've define are soundly transmutable, you usually 32 | //! must mark them with the `#[repr(C)]` attribute. 33 | //! 34 | //! ### Transmuting Owned Values 35 | //! [transmute-owned]: #transmuting-owned-values 36 | //! 37 | //! Transmutations involving owned values must adhere to two rules to be sound. 38 | //! They must: 39 | //! * [preserve or broaden the bit validity][owned-validity], and 40 | //! * [preserve or shrink the size][owned-size]. 41 | //! 42 | //! #### Preserve or Broaden Bit Validity 43 | //! [owned-validity]: #preserve-or-broaden-bit-validity 44 | //! 45 | //! For each _ith_ of the destination type, all possible 46 | //! instantiations of the _ith_ byte of the source type must be a 47 | //! bit-valid instance of the _ith_ byte of the destination type. 48 | //! 49 | //! For example, we are permitted us to transmute a [`NonZeroU8`] into a [`u8`]: 50 | //! ```rust 51 | //! # use typic::docs::prelude::*; 52 | //! let _ : u8 = NonZeroU8::new(1).unwrap().transmute_into(); 53 | //! ``` 54 | //! ...because all possible instances of [`NonZeroU8`] are also valid instances 55 | //! of [`u8`]. However, transmuting a [`u8`] into a [`NonZeroU8`] is forbidden: 56 | //! ```compile_fail 57 | //! # use typic::docs::prelude::*; 58 | //! let _ : NonZeroU8 = u8::default().transmute_into(); // Compile Error! 59 | //! ``` 60 | //! ...because not all instances of [`u8`] are valid instances of [`NonZeroU8`]. 61 | //! 62 | //! Another example: While laying out certain types, rust may insert padding 63 | //! bytes between the layouts of fields. In the below example `Padded` has two 64 | //! padding bytes, while `Packed` has none: 65 | //! ```rust 66 | //! # use typic::docs::prelude::*; 67 | //! #[typic::repr(C)] 68 | //! #[derive(Default, StableABI)] 69 | //! struct Padded(pub u8, pub u16, pub u8); 70 | //! 71 | //! #[typic::repr(C)] 72 | //! #[derive(Default, StableABI)] 73 | //! struct Packed(pub u16, pub u16, pub u16); 74 | //! 75 | //! assert_eq!(mem::size_of::(), mem::size_of::()); 76 | //! ``` 77 | //! 78 | //! We may safely transmute from `Packed` to `Padded`: 79 | //! ```rust 80 | //! # use typic::docs::prelude::*; 81 | //! let _ : Padded = Packed::default().transmute_into(); 82 | //! ``` 83 | //! ...but not from `Padded` to `Packed`: 84 | //! ```compile_fail 85 | //! # use typic::docs::prelude::*; 86 | //! let _ : Packed = Padded::default().transmute_into(); // Compile Error! 87 | //! ``` 88 | //! ...because doing so would expose two uninitialized padding bytes in `Padded` 89 | //! as if they were initialized bytes in `Packed`. 90 | //! 91 | //! #### Preserve or Shrink Size 92 | //! [owned-size]: #preserve-or-shrink-size 93 | //! 94 | //! It's completely safe to transmute into a type with fewer bytes than the 95 | //! destination type; e.g.: 96 | //! ```rust 97 | //! # use typic::docs::prelude::*; 98 | //! let _ : u8 = u64::default().transmute_into(); 99 | //! ``` 100 | //! This transmute truncates away the final three bytes of the `u64` value. 101 | //! 102 | //! A value may ***not*** be transmuted into a type of greater size: 103 | //! ```compile_fail 104 | //! # use typic::docs::prelude::*; 105 | //! let _ : u64 = u8::default().transmute_into(); // Compile Error! 106 | //! ``` 107 | //! 108 | //! ### Transmuting References 109 | //! [transmute-references]: #transmuting-references 110 | //! 111 | //! The [restrictions above that to transmuting owned values][transmute-owned], 112 | //! also apply to transmuting references. However, references carry a few 113 | //! additional restrictions. A [sound transmutation](#sound-transmutation) must: 114 | //! - [preserve or relax alignment][reference-alignment], 115 | //! - [preserve or shrink lifetimes][reference-lifetimes], 116 | //! - [preserve or shrink mutability][reference-mutability], and 117 | //! - [preserve validity][reference-validity]. 118 | //! 119 | //! #### Preserve or Relax Alignment 120 | //! [reference-alignment]: #preserve-or-relax-alignment 121 | //! 122 | //! You may transmute a reference into reference of more relaxed alignment: 123 | //! ```rust 124 | //! # use typic::docs::prelude::*; 125 | //! let _: &[u8; 0] = (&[0u16; 0]).transmute_into(); 126 | //! ``` 127 | //! 128 | //! However, you may **not** transmute a reference into a reference of stricter 129 | //! alignment: 130 | //! ```compile_fail 131 | //! # use typic::docs::prelude::*; 132 | //! let _: &[u16; 0] = (&[0u8; 0]).transmute_into(); // Compile Error! 133 | //! ``` 134 | //! 135 | //! #### Preserve or Shrink Lifetimes 136 | //! [reference-lifetimes]: #preserve-or-shrink-lifetimes 137 | //! 138 | //! You may transmute a reference into reference of lesser lifetime: 139 | //! ```rust 140 | //! # use typic::docs::prelude::*; 141 | //! fn shrink<'a>() -> &'a u8 { 142 | //! static long : &'static u8 = &16; 143 | //! long 144 | //! } 145 | //! ``` 146 | //! 147 | //! However, you may **not** transmute a reference into a reference of greater 148 | //! lifetime: 149 | //! ```compile_fail 150 | //! # use typic::docs::prelude::*; 151 | //! fn extend<'a>(short: &'a u8) -> &'static u8 { 152 | //! static long : &'static u8 = &16; 153 | //! short.transmute_into() 154 | //! } 155 | //! ``` 156 | //! 157 | //! #### Preserve or Shrink Mutability 158 | //! [reference-mutability]: #preserve-or-shrink-mutability 159 | //! 160 | //! You may preserve or decrease the mutability of a reference through 161 | //! transmutation: 162 | //! ```rust 163 | //! # use typic::docs::prelude::*; 164 | //! let _: &u8 = (&42u8).transmute_into(); 165 | //! let _: &u8 = (&mut 42u8).transmute_into(); 166 | //! ``` 167 | //! 168 | //! However, you may **not** transmute an immutable reference into a mutable 169 | //! reference: 170 | //! ```compile_fail 171 | //! # use typic::docs::prelude::*; 172 | //! let _: &mut u8 = (&42u8).transmute_into(); // Compile Error! 173 | //! ``` 174 | //! 175 | //! #### Preserve Validity 176 | //! [reference-validity]: #preserve-validity 177 | //! 178 | //! Unlike transmutations of owned values, the transmutation of a reference may 179 | //! also not expand the bit-validity of the referenced type. For instance: 180 | //! 181 | //! ```compile_fail 182 | //! # use typic::docs::prelude::*; 183 | //! let mut x = NonZeroU8::new(42).unwrap(); 184 | //! { 185 | //! let y : &mut u8 = (&mut x).transmute_into(); // Compile Error! 186 | //! *y = 0; 187 | //! } 188 | //! 189 | //! let z : NonZeroU8 = x; 190 | //! ``` 191 | //! If this example did not produce a compile error, the value of `z` would not 192 | //! be a bit-valid instance of its type. 193 | 194 | #[doc(inline)] 195 | pub use crate::transmute::{ 196 | unsafe_transmute, 197 | UnsafeTransmuteFrom, 198 | UnsafeTransmuteInto, 199 | UnsafeTransmuteOptions 200 | }; 201 | 202 | /// Configuration options for ***sound*** transmutations. 203 | pub mod neglect { 204 | #[doc(inline)] 205 | pub use crate::transmute::neglect::{ 206 | Alignment, 207 | Transparency, 208 | Stability, 209 | }; 210 | } 211 | -------------------------------------------------------------------------------- /typic/tests/derive.rs: -------------------------------------------------------------------------------- 1 | #![feature(concat_idents)] 2 | 3 | use core::mem::align_of; 4 | use static_assertions::*; 5 | use typic::{self, internal::*}; 6 | 7 | mod zst { 8 | use super::*; 9 | 10 | #[typic::repr(C)] 11 | struct ZST_C; 12 | 13 | #[typic::repr()] 14 | struct ZST_Rust; 15 | 16 | #[typic::repr(packed)] 17 | struct ZST_Packed; 18 | 19 | const_assert_eq![1, align_of::()]; 20 | const_assert_eq![1, align_of::()]; 21 | const_assert_eq![1, align_of::()]; 22 | 23 | assert_type_eq_all![ 24 | MinAlign, 25 | ::ReprAlign, 26 | ::ReprAlign, 27 | ::ReprAlign, 28 | ]; 29 | 30 | assert_type_eq_all![ 31 | MaxAlign, 32 | ::ReprPacked, 33 | ::ReprPacked, 34 | ::ReprPacked, 35 | ]; 36 | } 37 | 38 | mod align_1 { 39 | use super::*; 40 | 41 | #[typic::repr(align(1))] 42 | struct Align1; 43 | 44 | const_assert_eq![1, align_of::()]; 45 | 46 | assert_type_eq_all!(::ReprAlign, MinAlign); 47 | assert_type_eq_all!(::ReprPacked, MaxAlign); 48 | } 49 | 50 | mod multi_align { 51 | use super::*; 52 | 53 | #[typic::repr(align(2), align(4))] 54 | struct Align2_4; 55 | 56 | #[typic::repr(align(4), align(2))] 57 | struct Align4_2; 58 | 59 | const_assert_eq![4, align_of::()]; 60 | const_assert_eq![4, align_of::()]; 61 | 62 | assert_type_eq_all![ 63 | U4, 64 | ::ReprAlign, 65 | ::ReprAlign, 66 | ]; 67 | } 68 | -------------------------------------------------------------------------------- /typic/tests/transmute.rs: -------------------------------------------------------------------------------- 1 | use core::mem::align_of; 2 | use core::num::NonZeroU8; 3 | use static_assertions::*; 4 | use typic::{self, transmute::StableTransmuteInto, stability::StableABI}; 5 | 6 | #[test] 7 | fn zst_transmute() { 8 | #[typic::repr(C)] 9 | #[derive(StableABI)] 10 | struct T; 11 | 12 | #[typic::repr(C)] 13 | #[derive(StableABI)] 14 | struct U; 15 | 16 | let _: U = T.transmute_into(); 17 | let _: U = U.transmute_into(); 18 | let _: T = U.transmute_into(); 19 | let _: T = T.transmute_into(); 20 | 21 | let _: &T = (&U).transmute_into(); 22 | let _: &T = (&T).transmute_into(); 23 | let _: &U = (&T).transmute_into(); 24 | let _: &U = (&U).transmute_into(); 25 | } 26 | 27 | #[test] 28 | fn small_transmute() { 29 | #[typic::repr(C)] 30 | #[derive(Default, StableABI)] 31 | struct T(pub u8, pub u8); 32 | 33 | #[typic::repr(C)] 34 | #[derive(Default, StableABI)] 35 | struct U(pub u16); 36 | 37 | let _: U = T::default().transmute_into(); 38 | let _: U = U::default().transmute_into(); 39 | let _: T = U::default().transmute_into(); 40 | let _: T = T::default().transmute_into(); 41 | } 42 | 43 | #[test] 44 | fn padding_transmute() { 45 | #[typic::repr(C)] 46 | #[derive(Default, StableABI)] 47 | struct Padded(pub u8, pub u16, pub u8); 48 | 49 | #[typic::repr(C)] 50 | #[derive(Default, StableABI)] 51 | struct Packed(pub u16, pub u16, pub u16); 52 | 53 | let _: Packed = Packed::default().transmute_into(); 54 | let _: Padded = Padded::default().transmute_into(); 55 | 56 | // Transmuting initialized bytes into padding bytes is sound. 57 | let _: Padded = Packed::default().transmute_into(); 58 | 59 | // Transmuting padding bytes into initialized bytes is unsound. 60 | assert_not_impl_any!(Padded: StableTransmuteInto); 61 | } 62 | 63 | #[test] 64 | fn arrays() { 65 | // The inner type of the array may be mutated 66 | let _: [u8; 4] = [0u16; 2].transmute_into(); 67 | let _: [u16; 2] = [0u8; 4].transmute_into(); 68 | 69 | // Arrays may be shrunk 70 | let _: [u8; 4] = [0u8; 5].transmute_into(); 71 | 72 | // Arrays may not be grown: 73 | assert_not_impl_any!([u8; 4]: StableTransmuteInto<[u8; 5]>); 74 | assert_not_impl_any!([u8; 4]: StableTransmuteInto<[u16; 4]>); 75 | } 76 | 77 | #[test] 78 | fn references() { 79 | // You may transmute to a less strictly aligned type: 80 | let _: &[u8; 0] = (&[0u16; 0]).transmute_into(); 81 | 82 | // ...but not a more strictly aligned type: 83 | assert_not_impl_any!(&'static [u8; 0]: StableTransmuteInto<&'static [u16; 0]>); 84 | 85 | // You cannot alter the validity with a pointer transmute: 86 | assert_not_impl_any!(&'static u8: StableTransmuteInto<&'static NonZeroU8>); 87 | assert_not_impl_any!(&'static NonZeroU8: StableTransmuteInto<&'static u8>); 88 | 89 | // You may decrease the size: 90 | let _: &u8 = (&0u16).transmute_into(); 91 | 92 | // ...but you cannot increase the size: 93 | assert_not_impl_any!(&'static u8: StableTransmuteInto<&'static u16>); 94 | 95 | // You cannot violate transparency: 96 | #[typic::repr(C)] 97 | #[derive(Default, StableABI)] 98 | pub struct A(u8); 99 | 100 | #[typic::repr(C)] 101 | #[derive(Default, StableABI)] 102 | pub struct B(pub u8); 103 | 104 | assert_not_impl_any!(&'static A: StableTransmuteInto<&'static B>); 105 | assert_not_impl_any!(&'static B: StableTransmuteInto<&'static A>); 106 | } 107 | -------------------------------------------------------------------------------- /typic/tests/transmute_stress.rs: -------------------------------------------------------------------------------- 1 | #![recursion_limit = "512"] 2 | 3 | use static_assertions::*; 4 | use typic::{self, stability::StableABI, transmute::StableTransmuteInto}; 5 | 6 | // Adapted From: 7 | // https://rust-lang.zulipchat.com/#narrow/stream/216762-project-safe-transmute/topic/typic/near/185459723 8 | fn stress() { 9 | #[typic::repr(C)] 10 | #[derive(Default, StableABI)] 11 | pub struct A( 12 | pub [u64; 1], 13 | pub [u64; 2], 14 | pub [u64; 3], 15 | pub [u64; 4], 16 | pub [u64; 5], 17 | pub [u64; 6], 18 | pub [u64; 7], 19 | pub [u64; 8], 20 | pub [u64; 9], 21 | pub [u64; 10], 22 | pub [u64; 11], 23 | pub [u64; 12], 24 | pub [u64; 13], 25 | pub [u64; 14], 26 | pub [u64; 15], 27 | pub [u64; 16], 28 | ); 29 | 30 | #[typic::repr(C)] 31 | #[derive(Default, StableABI)] 32 | pub struct B( 33 | pub [u64; 16], 34 | pub [u64; 15], 35 | pub [u64; 14], 36 | pub [u64; 13], 37 | pub [u64; 12], 38 | pub [u64; 11], 39 | pub [u64; 10], 40 | pub [u64; 9], 41 | pub [u64; 8], 42 | pub [u64; 7], 43 | pub [u64; 6], 44 | pub [u64; 5], 45 | pub [u64; 4], 46 | pub [u64; 3], 47 | pub [u64; 2], 48 | pub [u64; 1], 49 | ); 50 | 51 | let _: A = B::default().transmute_into(); 52 | } 53 | --------------------------------------------------------------------------------