abi_stable/sabi_types/rmut.rs
1use std::{
2 fmt::{self, Display},
3 marker::PhantomData,
4 ptr::NonNull,
5};
6
7use crate::{
8 pointer_trait::{AsMutPtr, AsPtr, CanTransmuteElement, GetPointerKind, PK_MutReference},
9 sabi_types::RRef,
10};
11
12/// Equivalent to `&'a mut T`,
13/// which allows a few more operations without causing Undefined Behavior.
14///
15/// # Purpose
16///
17/// This type is used as the `&mut self` parameter in abi_stable trait objects
18/// because it can be soundly transmuted
19/// to point to other smaller but compatible types, then back to the original type.
20///
21/// This crate is tested with [miri] to detect bugs in unsafe code,
22/// which implements the [Stacked Borrows model].
23/// Because that model forbids `&mut T` to `&mut ()` to `&mut T` transmutes
24/// (when `T` isn't zero-sized),
25/// it required defining `RMut` to allow a mutable-reference-like type that can be transmuted.
26///
27/// # Example
28///
29/// This example demonstrates how a simple `&mut dyn Any`-like type can be implemented.
30///
31/// ```rust
32/// use abi_stable::{marker_type::ErasedObject, std_types::UTypeId, RMut};
33///
34/// fn main() {
35/// let mut value = WithTypeId::new(5u32);
36/// let mut clone = value.clone();
37/// let mut erased = value.erase();
38///
39/// assert_eq!(WithTypeId::downcast::<i32>(erased.reborrow()), None);
40/// assert_eq!(WithTypeId::downcast::<bool>(erased.reborrow()), None);
41/// assert_eq!(
42/// WithTypeId::downcast::<u32>(erased.reborrow()),
43/// Some(&mut clone)
44/// );
45/// }
46///
47/// // `#[repr(C))]` with a trailing `T` field is required for soundly transmuting from
48/// // `RMut<'a, WithTypeId<T>>` to `RMut<'a, WithTypeId<ErasedObject>>`.
49/// #[repr(C)]
50/// #[derive(Debug, PartialEq, Clone)]
51/// struct WithTypeId<T> {
52/// type_id: UTypeId,
53/// value: T,
54/// }
55///
56/// impl<T> WithTypeId<T> {
57/// pub fn new(value: T) -> Self
58/// where
59/// T: 'static,
60/// {
61/// Self {
62/// type_id: UTypeId::new::<T>(),
63/// value,
64/// }
65/// }
66///
67/// pub fn erase(&mut self) -> RMut<'_, WithTypeId<ErasedObject>> {
68/// unsafe { RMut::new(self).transmute::<WithTypeId<ErasedObject>>() }
69/// }
70/// }
71///
72/// impl WithTypeId<ErasedObject> {
73/// pub fn downcast<T>(this: RMut<'_, Self>) -> Option<&mut WithTypeId<T>>
74/// where
75/// T: 'static,
76/// {
77/// if this.get().type_id == UTypeId::new::<T>() {
78/// // safety: we checked that type parameter was `T`
79/// unsafe { Some(this.transmute_into_mut::<WithTypeId<T>>()) }
80/// } else {
81/// None
82/// }
83/// }
84/// }
85///
86///
87/// ```
88///
89/// <span id="type-prefix-exp"></span>
90/// # Type Prefix
91///
92/// A type parameter `U` is considered a prefix of `T` in all of these cases:
93///
94/// - `U` is a zero-sized type with an alignment equal or lower than `T`
95///
96/// - `U` is a `#[repr(transparent)]` wrapper over `T`
97///
98/// - `U` and `T` are both `#[repr(C)]` structs,
99/// in which `T` starts with the fields of `U` in the same order,
100/// and `U` has an alignment equal to or lower than `T`.
101///
102/// Please note that it can be unsound to transmute a non-local
103/// type if it has private fields,
104/// since it may assume it was constructed in a particular way.
105///
106/// [Stacked Borrows model]:
107/// https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md
108///
109/// [miri]: https://github.com/rust-lang/miri
110///
111#[repr(transparent)]
112#[derive(StableAbi)]
113#[sabi(bound(T:'a))]
114pub struct RMut<'a, T> {
115 ref_: NonNull<T>,
116 _marker: PhantomData<crate::utils::MutRef<'a, T>>,
117}
118
119impl<'a, T> Display for RMut<'a, T>
120where
121 T: Display,
122{
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 Display::fmt(self.get(), f)
125 }
126}
127
128unsafe impl<'a, T> Sync for RMut<'a, T> where &'a T: Sync {}
129
130unsafe impl<'a, T> Send for RMut<'a, T> where &'a T: Send {}
131
132shared_impls! {
133 mod=static_ref_impls
134 new_type=RMut['a][T],
135 original_type=AAAA,
136 deref_approach=(method = get),
137}
138
139impl<'a, T> RMut<'a, T> {
140 /// Constructs this RMut from a mutable reference
141 ///
142 /// # Example
143 ///
144 /// ```rust
145 /// use abi_stable::RMut;
146 ///
147 /// let mut foo = 3;
148 /// let mut rmut = RMut::new(&mut foo);
149 /// *rmut.get_mut() += 10;
150 ///
151 /// assert_eq!(*rmut.get(), 13);
152 /// assert_eq!(foo, 13);
153 ///
154 /// ```
155 #[inline(always)]
156 pub fn new(ref_: &'a mut T) -> Self {
157 unsafe {
158 Self {
159 ref_: NonNull::new_unchecked(ref_),
160 _marker: PhantomData,
161 }
162 }
163 }
164
165 /// Constructs this RMut from a raw pointer.
166 ///
167 /// # Safety
168 ///
169 /// You must ensure that the raw pointer is valid for the `'a` lifetime,
170 /// points to a fully initialized and aligned `T`,
171 /// and that this is the only active pointer to that value.
172 ///
173 /// # Example
174 ///
175 /// ```rust
176 /// use abi_stable::RMut;
177 ///
178 /// let mut foo = 3u32;
179 /// // safety:
180 /// // `&mut foo` is casted to a pointer to a compatible type (`u32` to `i32`),
181 /// // `rmut` is only used for the lifetime of foo,
182 /// // and is the only active pointer to `foo` while it's used.
183 /// let mut rmut = unsafe { RMut::from_raw((&mut foo) as *mut u32 as *mut i32) };
184 /// *rmut.get_mut() -= 4;
185 ///
186 /// assert_eq!(*rmut.get(), -1);
187 /// assert_eq!(foo, !0);
188 ///
189 /// ```
190 #[inline(always)]
191 pub const unsafe fn from_raw(ref_: *mut T) -> Self
192 where
193 T: 'a,
194 {
195 Self {
196 ref_: unsafe { NonNull::new_unchecked(ref_) },
197 _marker: PhantomData,
198 }
199 }
200
201 /// Reborrows this `RMut`, with a shorter lifetime.
202 ///
203 /// This allows passing an `RMut` to functions multiple times,
204 /// but with a shorter lifetime argument.
205 ///
206 /// # Example
207 ///
208 /// ```rust
209 /// use abi_stable::RMut;
210 ///
211 /// let mut foo = 3;
212 /// let mut rmut = RMut::new(&mut foo);
213 ///
214 /// assert_eq!(mutate(rmut.reborrow()), 6);
215 /// assert_eq!(mutate(rmut.reborrow()), 12);
216 /// assert_eq!(mutate(rmut.reborrow()), 24);
217 ///
218 /// // last use of rmut, so it can be moved instead of being reborrowed.
219 /// assert_eq!(mutate(rmut), 48);
220 ///
221 /// fn mutate(mut rmut: RMut<'_, u32>) -> u32 {
222 /// *rmut.get_mut() *= 2;
223 /// rmut.get_copy()
224 /// }
225 ///
226 /// ```
227 #[inline(always)]
228 pub fn reborrow(&mut self) -> RMut<'_, T> {
229 RMut {
230 ref_: self.ref_,
231 _marker: PhantomData,
232 }
233 }
234
235 /// Reborrows this `RMut` into a shared reference.
236 ///
237 /// Note that because the reference reborrows this `RMut<'a, T>`
238 /// its lifetime argument is strictly smaller.
239 /// To turn an `RMut<'a, T>` into a `&'a T` (with the same lifetime argument)
240 /// you can use [`into_ref`](#method.into_ref).
241 ///
242 ///
243 /// # Example
244 ///
245 /// ```rust
246 /// use abi_stable::RMut;
247 ///
248 /// let mut val = 89;
249 /// let rmut = RMut::new(&mut val);
250 ///
251 /// assert_eq!(rmut.get(), &89);
252 ///
253 /// ```
254 ///
255 /// ### Lifetimes
256 ///
257 /// This demonstrates when `into_ref` works, but `get` doesn't.
258 ///
259 /// ```rust
260 /// # use abi_stable::RMut;
261 /// fn stuff<'a>(x: RMut<'a, i32>) -> &'a i32 {
262 /// x.into_ref()
263 /// }
264 /// ```
265 ///
266 /// This doesn't compile, because `get` reborrows `foo`.
267 /// ```compile_fail
268 /// # use abi_stable::RMut;
269 /// fn stuff<'a>(foo: RMut<'a, i32>) -> &'a i32 {
270 /// foo.get()
271 /// }
272 /// ```
273 #[inline(always)]
274 pub const fn get(&self) -> &T {
275 unsafe { crate::utils::deref!(self.ref_.as_ptr()) }
276 }
277
278 /// Copies the value that this `RMut` points to.
279 ///
280 /// # Example
281 ///
282 /// ```rust
283 /// use abi_stable::RMut;
284 ///
285 /// let mut val = "hello";
286 /// let mut rmut = RMut::new(&mut val);
287 ///
288 /// *rmut.get_mut() = "world";
289 ///
290 /// assert_eq!(rmut.get_copy(), "world");
291 ///
292 /// ```
293 #[inline(always)]
294 pub const fn get_copy(&self) -> T
295 where
296 T: Copy,
297 {
298 unsafe { *(self.ref_.as_ptr() as *const T) }
299 }
300
301 /// Converts this `RMut<'a, T>` into a `&'a T`
302 ///
303 /// # Example
304 ///
305 /// ```rust
306 /// use abi_stable::RMut;
307 ///
308 /// let mut val = 89;
309 ///
310 /// assert_eq!(mutate(RMut::new(&mut val)), &44);
311 ///
312 /// fn mutate(mut rmut: RMut<'_, u32>) -> &u32 {
313 /// *rmut.get_mut() /= 2;
314 /// rmut.into_ref()
315 /// }
316 ///
317 /// ```
318 ///
319 #[inline(always)]
320 pub const fn into_ref(self) -> &'a T {
321 unsafe { crate::utils::deref!(self.ref_.as_ptr()) }
322 }
323
324 /// Reborrows this `RMut` into a mutable reference.
325 ///
326 /// Note that because the mutable reference reborrows this `RMut<'a, T>`
327 /// its lifetime argument is strictly smaller.
328 /// To turn an `RMut<'a, T>` into a `&'a mut T` (with the same lifetime argument)
329 /// you can use [`into_mut`](#method.into_mut).
330 ///
331 /// # Example
332 ///
333 /// ```rust
334 /// use abi_stable::RMut;
335 ///
336 /// let mut val = 89;
337 /// let mut rmut = RMut::new(&mut val);
338 ///
339 /// assert_eq!(rmut.get_mut(), &mut 89);
340 ///
341 /// *rmut.get_mut() += 10;
342 ///
343 /// assert_eq!(rmut.get_mut(), &mut 99);
344 ///
345 /// ```
346 ///
347 /// ### Lifetimes
348 ///
349 /// This demonstrates when `into_mut` works, but `get_mut` doesn't.
350 ///
351 /// ```rust
352 /// # use abi_stable::RMut;
353 /// fn stuff<'a>(x: RMut<'a, i32>) -> &'a mut i32 {
354 /// x.into_mut()
355 /// }
356 /// ```
357 ///
358 /// This doesn't compile, because `get_mut` reborrows `foo`.
359 /// ```compile_fail
360 /// # use abi_stable::RMut;
361 /// fn stuff<'a>(mut foo: RMut<'a, i32>) -> &'a mut i32 {
362 /// foo.get_mut()
363 /// }
364 /// ```
365 #[inline(always)]
366 pub fn get_mut(&mut self) -> &mut T {
367 unsafe { &mut *self.ref_.as_ptr() }
368 }
369
370 /// Converts this `RMut<'a, T>` into a `&'a mut T`
371 ///
372 /// # Example
373 ///
374 /// ```rust
375 /// use abi_stable::RMut;
376 ///
377 /// let mut val = 13;
378 ///
379 /// let rmut = RMut::new(&mut val);
380 ///
381 /// assert_eq!(rmut.get(), &13);
382 ///
383 /// *rmut.into_mut() += 8;
384 ///
385 /// assert_eq!(val, 21);
386 ///
387 /// ```
388 #[inline(always)]
389 pub fn into_mut(self) -> &'a mut T {
390 unsafe { &mut *self.ref_.as_ptr() }
391 }
392
393 /// Reborrows this `RMut` as a const raw pointer.
394 ///
395 /// # Example
396 ///
397 /// ```rust
398 /// use abi_stable::RMut;
399 ///
400 /// let mut val = 34;
401 /// let rmut = RMut::new(&mut val);
402 ///
403 /// unsafe {
404 /// assert_eq!(*rmut.as_ptr(), 34);
405 /// }
406 /// ```
407 #[inline]
408 pub const fn as_ptr(&self) -> *const T {
409 self.ref_.as_ptr()
410 }
411
412 /// Reborrows this `RMut` as a mutable raw pointer.
413 ///
414 /// # Example
415 ///
416 /// ```rust
417 /// use abi_stable::RMut;
418 ///
419 /// let mut val = 34;
420 /// let mut rmut = RMut::new(&mut val);
421 ///
422 /// unsafe {
423 /// rmut.as_mut_ptr().write(7);
424 ///
425 /// *rmut.as_mut_ptr() *= 2;
426 ///
427 /// assert_eq!(val, 14);
428 /// }
429 /// ```
430 #[inline]
431 pub fn as_mut_ptr(&mut self) -> *mut T {
432 self.ref_.as_ptr()
433 }
434
435 /// Converts this `RMut<'a, T>` into a `*mut T`
436 ///
437 /// # Example
438 ///
439 /// ```rust
440 /// use abi_stable::RMut;
441 ///
442 /// let mut val = 89;
443 /// let rmut = RMut::new(&mut val);
444 ///
445 /// unsafe {
446 /// let ptr = rmut.into_raw();
447 ///
448 /// ptr.write(27);
449 ///
450 /// *ptr += 2;
451 ///
452 /// assert_eq!(val, 29);
453 /// }
454 /// ```
455 #[inline]
456 pub const fn into_raw(self) -> *mut T {
457 self.ref_.as_ptr()
458 }
459
460 /// Transmutes this `RMut<'a, T>` to a `*mut U`.
461 ///
462 /// # Example
463 ///
464 /// ```rust
465 /// use abi_stable::RMut;
466 ///
467 /// let mut val = Direction::Up;
468 /// let rmut = RMut::new(&mut val);
469 ///
470 /// assert_eq!(rmut.get(), &Direction::Up);
471 ///
472 /// let ptr = rmut.transmute_into_raw::<u8>();
473 ///
474 /// unsafe {
475 /// assert_eq!(*ptr, 2);
476 /// *ptr = 3;
477 /// }
478 ///
479 /// assert_eq!(val, Direction::Down);
480 ///
481 /// #[repr(u8)]
482 /// #[derive(Debug, PartialEq)]
483 /// enum Direction {
484 /// Left = 0,
485 /// Right = 1,
486 /// Up = 2,
487 /// Down = 3,
488 /// }
489 ///
490 /// ```
491 #[inline(always)]
492 pub const fn transmute_into_raw<U>(self) -> *mut U {
493 self.ref_.as_ptr() as *mut U
494 }
495
496 /// Transmutes this `RMut<'a, T>` to a `&'a mut U`.
497 ///
498 /// # Safety
499 ///
500 /// Either of these must be the case:
501 ///
502 /// - [`U` is a prefix of `T`](#type-prefix-exp)
503 ///
504 /// - `RMut<'a, U>` was the original type of this `RMut<'a, T>`.
505 ///
506 /// # Example
507 ///
508 /// ```rust
509 /// use abi_stable::RMut;
510 ///
511 /// let mut val = 13u8;
512 /// let rmut = RMut::new(&mut val);
513 ///
514 /// assert_eq!(rmut.get(), &13);
515 ///
516 /// unsafe {
517 /// *rmut.transmute_into_mut::<i8>() = -1;
518 /// }
519 ///
520 /// assert_eq!(val, 255);
521 ///
522 /// ```
523 #[inline(always)]
524 pub unsafe fn transmute_into_mut<U>(self) -> &'a mut U
525 where
526 U: 'a,
527 {
528 unsafe { &mut *(self.ref_.as_ptr() as *mut U) }
529 }
530
531 /// Transmutes this `RMut<'a, T>` to a `RMut<'a,U>`.
532 ///
533 /// # Safety
534 ///
535 /// Either of these must be the case:
536 ///
537 /// - [`U` is a prefix of `T`](#type-prefix-exp)
538 ///
539 /// - `RMut<'a, U>` was the original type of this `RMut<'a, T>`.
540 ///
541 /// # Example
542 ///
543 /// ```rust
544 /// use abi_stable::RMut;
545 ///
546 /// let mut val: [u32; 3] = [2, 3, 0];
547 /// let mut rmut = RMut::new(&mut val);
548 ///
549 /// unsafe {
550 /// // safety:
551 /// // it's sound to transmute mutable references of arrays into shorter arrays.
552 /// //
553 /// // The `.reborrow()` prevents the `rmut` from being consumed.
554 /// compute_next(rmut.reborrow().transmute::<[u32; 2]>());
555 /// assert_eq!(rmut.get_copy(), [3, 5, 0]);
556 ///
557 /// compute_next(rmut.reborrow().transmute::<[u32; 2]>());
558 /// assert_eq!(rmut.get_copy(), [5, 8, 0]);
559 ///
560 /// // last use of `rmut`, so no need to reborrow
561 /// compute_next(rmut.transmute::<[u32; 2]>());
562 /// }
563 ///
564 /// assert_eq!(val, [8, 13, 0]);
565 ///
566 /// fn compute_next(rmut: RMut<'_, [u32; 2]>) {
567 /// let [v0, v1] = rmut.into_mut();
568 /// let next = *v0 + *v1;
569 /// *v0 = std::mem::replace(v1, next);
570 /// }
571 /// ```
572 #[inline(always)]
573 pub const unsafe fn transmute<U>(self) -> RMut<'a, U>
574 where
575 U: 'a,
576 {
577 unsafe { RMut::from_raw(self.ref_.as_ptr() as *mut U) }
578 }
579
580 /// Reborrows this `RMut<'a, T>` into an `RRef<'_, T>`
581 ///
582 /// # Example
583 ///
584 /// ```rust
585 /// use abi_stable::{RMut, RRef};
586 ///
587 /// let mut val = 77;
588 /// let rmut = RMut::new(&mut val);
589 ///
590 /// for _ in 0..10 {
591 /// assertion(rmut.as_rref());
592 /// }
593 ///
594 /// fn assertion(rref: RRef<'_, u32>) {
595 /// assert_eq!(rref.get_copy(), 77);
596 /// }
597 /// ```
598 #[inline(always)]
599 #[allow(clippy::needless_lifetimes)]
600 pub const fn as_rref<'r>(&'r self) -> RRef<'r, T> {
601 unsafe { RRef::from_raw(self.ref_.as_ptr()) }
602 }
603
604 /// Converts this `RMut<'a, T>` to an `RRef<'_, T>`
605 ///
606 /// # Example
607 ///
608 /// ```rust
609 /// use abi_stable::{RMut, RRef};
610 ///
611 /// let mut val = 0;
612 /// let rmut = RMut::new(&mut val);
613 ///
614 /// assertion(rmut.into_rref());
615 ///
616 /// fn assertion(rref: RRef<'_, u32>) {
617 /// assert_eq!(rref.get_copy(), 0);
618 /// }
619 /// ```
620 #[inline(always)]
621 pub const fn into_rref(self) -> RRef<'a, T> {
622 unsafe { RRef::from_raw(self.ref_.as_ptr()) }
623 }
624}
625
626unsafe impl<'a, T> AsPtr for RMut<'a, T> {
627 #[inline(always)]
628 fn as_ptr(&self) -> *const T {
629 self.ref_.as_ptr() as *const T
630 }
631 #[inline(always)]
632 fn as_rref(&self) -> RRef<'_, T> {
633 unsafe { RRef::from_raw(self.ref_.as_ptr() as *const T) }
634 }
635}
636
637unsafe impl<'a, T> AsMutPtr for RMut<'a, T> {
638 #[inline(always)]
639 fn as_mut_ptr(&mut self) -> *mut T {
640 self.ref_.as_ptr()
641 }
642
643 #[inline(always)]
644 fn as_rmut(&mut self) -> RMut<'_, T> {
645 self.reborrow()
646 }
647}
648
649unsafe impl<'a, T> GetPointerKind for RMut<'a, T> {
650 type Kind = PK_MutReference;
651
652 type PtrTarget = T;
653}
654
655unsafe impl<'a, T, U> CanTransmuteElement<U> for RMut<'a, T>
656where
657 U: 'a,
658{
659 type TransmutedPtr = RMut<'a, U>;
660
661 #[inline(always)]
662 unsafe fn transmute_element_(self) -> Self::TransmutedPtr {
663 unsafe { self.transmute() }
664 }
665}
666
667#[cfg(test)]
668mod tests {
669 use super::*;
670
671 #[test]
672 fn construction_test() {
673 unsafe {
674 let val: *mut i32 = &mut 3;
675 let mut rmut = RMut::from_raw(val);
676 *rmut.get_mut() += 5;
677 assert_eq!(rmut.get_copy(), 8);
678 }
679 {
680 let val = &mut 3;
681 let mut rmut = RMut::new(val);
682 *rmut.get_mut() += 5;
683 assert_eq!(rmut.get_copy(), 8);
684 }
685 }
686
687 #[test]
688 fn access() {
689 let mut num = 5;
690 let mut mutref = RMut::new(&mut num);
691
692 assert_eq!(*mutref.get_mut(), 5);
693 *mutref.get_mut() = 21;
694
695 assert_eq!(*mutref.get(), 21);
696 assert_eq!(mutref.get_copy(), 21);
697 assert_eq!(*mutref.reborrow().into_ref(), 21);
698
699 *mutref.reborrow().into_mut() = 34;
700
701 unsafe {
702 assert_eq!(*mutref.as_ptr(), 34);
703
704 *mutref.as_mut_ptr() = 55;
705
706 assert_eq!(*mutref.reborrow().into_raw(), 55);
707 *mutref.reborrow().into_raw() = 89;
708 }
709 assert_eq!(num, 89);
710 }
711
712 #[test]
713 fn transmutes() {
714 let mut num = 0u8;
715
716 unsafe {
717 let ptr = RMut::new(&mut num).transmute_into_raw::<Enum>();
718 assert_eq!(*ptr, Enum::Foo);
719
720 ptr.write(Enum::Bar);
721 assert_eq!(*ptr, Enum::Bar);
722 assert_eq!(num, 1);
723 }
724 unsafe {
725 let mref = RMut::new(&mut num).transmute_into_mut::<Enum>();
726 assert_eq!(*mref, Enum::Bar);
727
728 *mref = Enum::Qux;
729 assert_eq!(*mref, Enum::Qux);
730 assert_eq!(num, 2);
731 }
732 unsafe {
733 let mut rmut = RMut::new(&mut num).transmute::<Enum>();
734 assert_eq!(rmut, RMut::new(&mut Enum::Qux));
735
736 *rmut.get_mut() = Enum::Foo;
737 assert_eq!(*rmut.get(), Enum::Foo);
738 assert_eq!(num, 0);
739 }
740 unsafe {
741 let mut rmut: RMut<'_, Enum> = RMut::new(&mut num).transmute_element_();
742 assert_eq!(rmut, RMut::new(&mut Enum::Foo));
743
744 *rmut.get_mut() = Enum::Bar;
745 assert_eq!(*rmut.get(), Enum::Bar);
746 assert_eq!(num, 1);
747 }
748 }
749
750 #[test]
751 fn as_rtype_test() {
752 let mut num = 0u8;
753 let mut rmut = RMut::new(&mut num);
754
755 assert_eq!(rmut.as_rref(), RRef::new(&0));
756 assert_eq!(rmut.reborrow().into_rref(), RRef::new(&0));
757
758 assert_eq!(rmut.as_rmut(), RMut::new(&mut 0));
759 }
760
761 #[derive(Debug, PartialEq)]
762 #[repr(u8)]
763 enum Enum {
764 Foo = 0,
765 Bar = 1,
766 Qux = 2,
767 }
768}