Skip to main content

wiggle/
lib.rs

1use std::borrow::Cow;
2use std::cell::UnsafeCell;
3use std::fmt;
4use std::mem;
5use std::ops::Range;
6use std::str;
7use wasmtime_environ::error::{Result, bail};
8
9pub use wiggle_macro::from_witx;
10
11pub use wasmtime_environ::error;
12pub use wiggle_macro::wasmtime_integration;
13
14pub use bitflags;
15
16#[cfg(feature = "wiggle_metadata")]
17pub use witx;
18
19mod guest_error;
20mod guest_type;
21mod region;
22
23pub use tracing;
24
25pub use guest_error::GuestError;
26pub use guest_type::{GuestErrorType, GuestType, GuestTypeTransparent};
27pub use region::Region;
28
29#[cfg(feature = "wasmtime")]
30pub mod wasmtime_crate {
31    pub use wasmtime::*;
32}
33
34/// Representation of guest memory for `wiggle`-generated trait methods.
35///
36/// Guest memory is represented as an array of bytes. Memories are either
37/// "unshared" or "shared". Unshared means that the host has exclusive access to
38/// the entire array of memory. This allows safe borrows into wasm linear
39/// memory. Shared memories can be modified at any time and are represented as
40/// an array of `UnsafeCell<u8>`.
41///
42/// This is generated by the `wiggle` bindings macros.
43pub enum GuestMemory<'a> {
44    Unshared(&'a mut [u8]),
45    Shared(&'a [UnsafeCell<u8>]),
46    /// An unshared Wasmtime memory accessed by range, so that only the ranges
47    /// written are considered modified (see
48    /// `wasmtime::Memory::data_ranges_and_store_data_mut`).
49    #[cfg(feature = "wasmtime")]
50    Ranges(wasmtime::MemoryRanges<'a>),
51}
52
53// manual impls are needed because of the `UnsafeCell` in the `Shared` branch
54// but this otherwise upholds send/sync invariants.
55unsafe impl Send for GuestMemory<'_> {}
56unsafe impl Sync for GuestMemory<'_> {}
57
58impl<'a> GuestMemory<'a> {
59    /// Read a value from the provided pointer.
60    ///
61    /// This method will delegate to `T`'s implementation of `read` which will
62    /// read a value from the `ptr` provided.
63    ///
64    /// # Errors
65    ///
66    /// An error is returned if `ptr` is out of bounds, misaligned, or otherwise
67    /// not valid to read from.
68    pub fn read<T>(&self, ptr: GuestPtr<T>) -> Result<T, GuestError>
69    where
70        T: GuestType,
71    {
72        T::read(self, ptr)
73    }
74
75    /// Writes the `val` provided to the `ptr` provided.
76    ///
77    /// This commit will write a `val` into a guest's linear memory. This will
78    /// delegate to `T`'s implementation of `write`.
79    ///
80    /// # Errors
81    ///
82    /// An error is returned if `ptr` is out of bounds, misaligned, or otherwise
83    /// not valid to read from.
84    pub fn write<T>(&mut self, ptr: GuestPtr<T>, val: T) -> Result<(), GuestError>
85    where
86        T: GuestType,
87    {
88        T::write(self, ptr, val)
89    }
90
91    /// Acquires a slice or owned copy of the memory pointed to by `ptr`.
92    ///
93    /// This method will attempt to borrow `ptr` directly from linear memory. If
94    /// memory is shared and cannot be borrowed directly then an owned copy is
95    /// returned instead.
96    ///
97    /// # Errors
98    ///
99    /// An error is returned if `ptr` is out of bounds, misaligned, or otherwise
100    /// not valid to read from.
101    pub fn as_cow(&self, ptr: GuestPtr<[u8]>) -> Result<Cow<'_, [u8]>, GuestError> {
102        match self {
103            GuestMemory::Shared(_) => Ok(Cow::Owned(self.to_vec(ptr)?)),
104            _ => match self.as_slice(ptr)? {
105                Some(slice) => Ok(Cow::Borrowed(slice)),
106                None => unreachable!(),
107            },
108        }
109    }
110
111    /// Same as [`GuestMemory::as_cow`] but for strings.
112    ///
113    /// # Errors
114    ///
115    /// An error is returned if `ptr` is out of bounds, misaligned, or otherwise
116    /// not valid to read from.
117    pub fn as_cow_str(&self, ptr: GuestPtr<str>) -> Result<Cow<'_, str>, GuestError> {
118        match self.as_cow(ptr.cast::<[u8]>())? {
119            Cow::Owned(bytes) => Ok(Cow::Owned(
120                String::from_utf8(bytes).map_err(|e| e.utf8_error())?,
121            )),
122            Cow::Borrowed(bytes) => Ok(Cow::Borrowed(std::str::from_utf8(bytes)?)),
123        }
124    }
125
126    /// Attempts to borrow a raw guest slice of memory pointed to by `ptr`.
127    ///
128    /// This method will attempt to return a raw pointer into guest memory. This
129    /// can only be done for `Unshared` memories. A `Shared` memory will return
130    /// `Ok(None)` here.
131    ///
132    /// # Errors
133    ///
134    /// An error is returned if `ptr` is out of bounds, misaligned, or otherwise
135    /// not valid to read from.
136    pub fn as_slice(&self, ptr: GuestPtr<[u8]>) -> Result<Option<&[u8]>, GuestError> {
137        let range = self.validate_range::<u8>(ptr.pointer.0, ptr.pointer.1)?;
138        match self {
139            GuestMemory::Unshared(slice) => Ok(Some(&slice[range])),
140            GuestMemory::Shared(_) => Ok(None),
141            #[cfg(feature = "wasmtime")]
142            GuestMemory::Ranges(memory) => Ok(Some(&memory.data()[range])),
143        }
144    }
145
146    /// Same as [`GuestMemory::as_slice`] but for strings.
147    pub fn as_str(&self, ptr: GuestPtr<str>) -> Result<Option<&str>, GuestError> {
148        match self.as_slice(ptr.cast())? {
149            Some(bytes) => Ok(Some(std::str::from_utf8(bytes)?)),
150            None => Ok(None),
151        }
152    }
153
154    /// Attempts return `ptr` as a raw slice of mutable bytes in wasm linear
155    /// memory.
156    ///
157    /// Like [`GuestMemory::as_slice`] this only works for `Unshared` memories
158    /// and will not work for `Shared` memories.
159    pub fn as_slice_mut(&mut self, ptr: GuestPtr<[u8]>) -> Result<Option<&mut [u8]>, GuestError> {
160        let range = self.validate_range::<u8>(ptr.pointer.0, ptr.pointer.1)?;
161        match self {
162            GuestMemory::Unshared(slice) => Ok(Some(&mut slice[range])),
163            GuestMemory::Shared(_) => Ok(None),
164            #[cfg(feature = "wasmtime")]
165            GuestMemory::Ranges(memory) => Ok(Some(
166                memory.data_range_mut(range).expect("range was validated"),
167            )),
168        }
169    }
170
171    /// Copies the data in the guest region into a [`Vec`].
172    ///
173    /// This is useful when one cannot use [`GuestMemory::as_slice`], e.g., when
174    /// pointing to a region of WebAssembly shared memory.
175    pub fn to_vec<T>(&self, ptr: GuestPtr<[T]>) -> Result<Vec<T>, GuestError>
176    where
177        T: GuestTypeTransparent + Copy,
178    {
179        let guest = self.validate_size_align::<T>(ptr.pointer.0, ptr.pointer.1)?;
180        let mut host = Vec::with_capacity(guest.len());
181
182        // SAFETY: The `guest_slice` variable is already a valid pointer into
183        // the guest's memory, and it may or may not be a pointer into shared
184        // memory. We can't naively use `.to_vec(..)` which could introduce data
185        // races but all that needs to happen is to copy data into our local
186        // `vec` as all the data is `Copy` and transparent anyway. For this
187        // purpose the `ptr::copy` function should be sufficient for copying
188        // over all the data.
189        //
190        // TODO: audit that this use of `std::ptr::copy` is safe with shared
191        // memory (https://github.com/bytecodealliance/wasmtime/issues/4203)
192        unsafe {
193            std::ptr::copy(guest.as_ptr().cast(), host.as_mut_ptr(), guest.len());
194            host.set_len(guest.len());
195        }
196        Ok(host)
197    }
198
199    /// Copies the data pointed to by `slice` into this guest region.
200    ///
201    /// This method is a *safe* method to copy data from the host to the guest.
202    /// This requires that `self` and `slice` have the same length. The pointee
203    /// type `T` requires the [`GuestTypeTransparent`] trait which is an
204    /// assertion that the representation on the host and on the guest is the
205    /// same.
206    ///
207    /// # Errors
208    ///
209    /// Returns an error if this guest pointer is out of bounds or if the length
210    /// of this guest pointer is not equal to the length of the slice provided.
211    pub fn copy_from_slice<T>(&mut self, slice: &[T], ptr: GuestPtr<[T]>) -> Result<(), GuestError>
212    where
213        T: GuestTypeTransparent + Copy,
214    {
215        if usize::try_from(ptr.len())? != slice.len() {
216            return Err(GuestError::SliceLengthsDiffer);
217        }
218        if slice.is_empty() {
219            return Ok(());
220        }
221
222        let guest = self.validate_size_align_mut::<T>(ptr.pointer.0, ptr.pointer.1)?;
223
224        // SAFETY: in the shared memory case, we copy and accept that
225        // the guest data may be concurrently modified. TODO: audit that
226        // this use of `std::ptr::copy` is safe with shared memory
227        // (https://github.com/bytecodealliance/wasmtime/issues/4203)
228        //
229        // Also note that the validity of `guest_slice` has already been
230        // determined by the `as_unsafe_slice_mut` call above.
231        assert_eq!(guest.len(), slice.len());
232        unsafe {
233            let guest: &[UnsafeCell<T>] = guest;
234            let guest: *const UnsafeCell<T> = guest.as_ptr();
235            let guest = guest.cast_mut().cast::<T>();
236            std::ptr::copy(slice.as_ptr(), guest, slice.len());
237        }
238        Ok(())
239    }
240
241    /// Validates a guest-relative pointer given various attributes, and returns
242    /// the corresponding host pointer.
243    ///
244    /// * `mem` - this is the guest memory being accessed.
245    /// * `offset` - this is the guest-relative pointer, an offset from the
246    ///   base.
247    /// * `len` - this is the number of length, in units of `T`, to return
248    ///   in the resulting slice.
249    ///
250    /// If the parameters are valid then this function will return a slice into
251    /// `mem` for units of `T`, assuming everything is in-bounds and properly
252    /// aligned. Additionally the byte-based `Region` is returned, used for borrows
253    /// later on.
254    fn validate_size_align<T>(&self, offset: u32, len: u32) -> Result<&[UnsafeCell<T>], GuestError>
255    where
256        T: GuestTypeTransparent,
257    {
258        let range = self.validate_range::<T>(offset, len)?;
259        let cells = match self {
260            GuestMemory::Unshared(s) => {
261                let s: &[u8] = s;
262                unsafe { &*(s as *const [u8] as *const [UnsafeCell<u8>]) }
263            }
264            GuestMemory::Shared(s) => s,
265            #[cfg(feature = "wasmtime")]
266            GuestMemory::Ranges(memory) => {
267                let s = memory.data();
268                unsafe { &*(s as *const [u8] as *const [UnsafeCell<u8>]) }
269            }
270        };
271        Self::align_cells(&cells[range.clone()], range)
272    }
273
274    /// Like `validate_size_align`, for writing: with
275    /// `GuestMemory::Ranges`, only the validated range is borrowed for
276    /// modification.
277    pub(crate) fn validate_size_align_mut<T>(
278        &mut self,
279        offset: u32,
280        len: u32,
281    ) -> Result<&[UnsafeCell<T>], GuestError>
282    where
283        T: GuestTypeTransparent,
284    {
285        match self {
286            #[cfg(feature = "wasmtime")]
287            GuestMemory::Ranges(memory) => {
288                let range = {
289                    let len = len
290                        .checked_mul(T::guest_size())
291                        .ok_or(GuestError::PtrOverflow)?;
292                    let region = Region { start: offset, len };
293                    let start = usize::try_from(offset)?;
294                    let end = start
295                        .checked_add(usize::try_from(len)?)
296                        .ok_or(GuestError::PtrOverflow)?;
297                    if end > memory.len() {
298                        return Err(GuestError::PtrOutOfBounds(region));
299                    }
300                    start..end
301                };
302                let s: &mut [u8] = memory
303                    .data_range_mut(range.clone())
304                    .expect("range was validated");
305                let cells = unsafe { &*(s as *const [u8] as *const [UnsafeCell<u8>]) };
306                Self::align_cells(cells, range)
307            }
308            _ => self.validate_size_align(offset, len),
309        }
310    }
311
312    /// Reinterprets `memory`, which holds `range` of guest memory, as `T`s,
313    /// failing if it is misaligned.
314    fn align_cells<T>(
315        memory: &[UnsafeCell<u8>],
316        range: Range<usize>,
317    ) -> Result<&[UnsafeCell<T>], GuestError>
318    where
319        T: GuestTypeTransparent,
320    {
321        // ... and then align it to `T`, failing if either the head or tail slices
322        // are nonzero in length. This `unsafe` here is from the standard library
323        // and should be ok since the input slice is `UnsafeCell<u8>` and the output
324        // slice is `UnsafeCell<T>`, meaning the only guarantee of the output is
325        // that it's valid addressable memory, still unsafe to actually access.
326        assert!(mem::align_of::<T>() <= T::guest_align());
327        let (start, mid, end) = unsafe { memory.align_to() };
328        if start.len() > 0 || end.len() > 0 {
329            let region = Region {
330                start: range.start as u32,
331                len: range.len() as u32,
332            };
333            return Err(GuestError::PtrNotAligned(region, T::guest_align() as u32));
334        }
335        Ok(mid)
336    }
337
338    fn validate_range<T>(&self, offset: u32, len: u32) -> Result<Range<usize>, GuestError>
339    where
340        T: GuestTypeTransparent,
341    {
342        let byte_len = len
343            .checked_mul(T::guest_size())
344            .ok_or(GuestError::PtrOverflow)?;
345        let region = Region {
346            start: offset,
347            len: byte_len,
348        };
349        let offset = usize::try_from(offset)?;
350        let byte_len = usize::try_from(byte_len)?;
351
352        let range = offset..offset + byte_len;
353        let oob = match self {
354            GuestMemory::Unshared(b) => b.get(range.clone()).is_none(),
355            GuestMemory::Shared(b) => b.get(range.clone()).is_none(),
356            #[cfg(feature = "wasmtime")]
357            GuestMemory::Ranges(memory) => range.end > memory.len(),
358        };
359        if oob {
360            Err(GuestError::PtrOutOfBounds(region))
361        } else {
362            Ok(range)
363        }
364    }
365
366    /// Returns whether this is a shared memory or not.
367    pub fn is_shared_memory(&self) -> bool {
368        matches!(self, GuestMemory::Shared(_))
369    }
370}
371
372/// A *guest* pointer.
373///
374/// This type represents a pointer from the guest that points into host memory.
375/// Internally a `GuestPtr` the offset into the memory that the pointer is
376/// pointing at. At this time this is always a 32-bit offset so this is not
377/// suitable for bindings where wasm has 64-bit addresses.
378///
379/// Presence of a [`GuestPtr`] does not imply any form of validity. Pointers can
380/// be out-of-bounds, misaligned, etc. It is safe to construct a `GuestPtr` with
381/// any offset at any time. Consider a `GuestPtr<T>` roughly equivalent to `*mut
382/// T`.
383///
384/// ## Slices and Strings
385///
386/// Note that the type parameter does not need to implement the `Sized` trait,
387/// so you can implement types such as this:
388///
389/// * `GuestPtr<str>` - a pointer to a guest string.
390/// * `GuestPtr<[T]>` - a pointer to a guest array.
391///
392/// Note that generated bindings won't use these types so you'll have to
393/// otherwise construct the types with `.cast()` or `.as_array()`. Unsized types
394/// track both the pointer and length in guest memory.
395///
396/// ## Type parameter and pointee
397///
398/// The `T` type parameter is largely intended for more static safety in Rust as
399/// well as having a better handle on what we're pointing to. A `GuestPtr<T>`,
400/// however, does not necessarily literally imply a guest pointer pointing to
401/// type `T`. Instead the [`GuestType`] trait is a layer of abstraction where
402/// `GuestPtr<T>` may actually be a pointer to `U` in guest memory, but you can
403/// construct a `T` from a `U`.
404///
405/// For example `GuestPtr<GuestPtr<T>>` is a valid type, but this is actually
406/// more equivalent to `GuestPtr<u32>` because guest pointers are always
407/// 32-bits. That being said you can create a `GuestPtr<T>` from a `u32`.
408///
409/// Additionally `GuestPtr<MyEnum>` will actually delegate, typically, to and
410/// implementation which loads the underlying data as `GuestPtr<u8>` (or
411/// similar) and then the bytes loaded are validated to fit within the
412/// definition of `MyEnum` before `MyEnum` is returned.
413///
414/// For more information see the [`GuestMemory::read`] and
415/// [`GuestMemory::write`] methods. In general though be extremely careful about
416/// writing `unsafe` code when working with a `GuestPtr` if you're not using one
417/// of the already-attached helper methods.
418#[repr(transparent)]
419pub struct GuestPtr<T: ?Sized + Pointee> {
420    pointer: T::Pointer,
421}
422
423impl<T: ?Sized + Pointee> GuestPtr<T> {
424    /// Creates a new `GuestPtr` from the given `mem` and `pointer` values.
425    ///
426    /// Note that for sized types like `u32`, `GuestPtr<T>`, etc, the `pointer`
427    /// value is a `u32` offset into guest memory. For slices and strings,
428    /// `pointer` is a `(u32, u32)` offset/length pair.
429    pub fn new(pointer: T::Pointer) -> GuestPtr<T> {
430        GuestPtr { pointer }
431    }
432
433    /// Returns the offset of this pointer in guest memory.
434    ///
435    /// Note that for sized types this returns a `u32`, but for slices and
436    /// strings it returns a `(u32, u32)` pointer/length pair.
437    pub fn offset(&self) -> T::Pointer {
438        self.pointer
439    }
440
441    /// Casts this `GuestPtr` type to a different type.
442    ///
443    /// This is a safe method which is useful for simply reinterpreting the type
444    /// parameter on this `GuestPtr`. Note that this is a safe method, where
445    /// again there's no guarantees about alignment, validity, in-bounds-ness,
446    /// etc of the returned pointer.
447    pub fn cast<U>(&self) -> GuestPtr<U>
448    where
449        U: Pointee<Pointer = T::Pointer> + ?Sized,
450    {
451        GuestPtr::new(self.pointer)
452    }
453
454    /// Performs pointer arithmetic on this pointer, moving the pointer forward
455    /// `amt` slots.
456    ///
457    /// This will either return the resulting pointer or `Err` if the pointer
458    /// arithmetic calculation would overflow around the end of the address
459    /// space.
460    pub fn add(&self, amt: u32) -> Result<GuestPtr<T>, GuestError>
461    where
462        T: GuestType + Pointee<Pointer = u32>,
463    {
464        let offset = amt
465            .checked_mul(T::guest_size())
466            .and_then(|o| self.pointer.checked_add(o));
467        let offset = match offset {
468            Some(o) => o,
469            None => return Err(GuestError::PtrOverflow),
470        };
471        Ok(GuestPtr::new(offset))
472    }
473
474    /// Returns a `GuestPtr` for an array of `T`s using this pointer as the
475    /// base.
476    pub fn as_array(&self, elems: u32) -> GuestPtr<[T]>
477    where
478        T: GuestType + Pointee<Pointer = u32>,
479    {
480        GuestPtr::new((self.pointer, elems))
481    }
482}
483
484impl<T> GuestPtr<[T]> {
485    /// For slices, specifically returns the relative pointer to the base of the
486    /// array.
487    ///
488    /// This is similar to `<[T]>::as_ptr()`
489    pub fn offset_base(&self) -> u32 {
490        self.pointer.0
491    }
492
493    /// For slices, returns the length of the slice, in elements.
494    pub fn len(&self) -> u32 {
495        self.pointer.1
496    }
497
498    /// Returns an iterator over interior pointers.
499    ///
500    /// Each item is a `Result` indicating whether it overflowed past the end of
501    /// the address space or not.
502    pub fn iter(&self) -> impl ExactSizeIterator<Item = Result<GuestPtr<T>, GuestError>> + '_
503    where
504        T: GuestType,
505    {
506        let base = self.as_ptr();
507        (0..self.len()).map(move |i| base.add(i))
508    }
509
510    /// Returns a `GuestPtr` pointing to the base of the array for the interior
511    /// type `T`.
512    pub fn as_ptr(&self) -> GuestPtr<T> {
513        GuestPtr::new(self.offset_base())
514    }
515
516    pub fn get(&self, index: u32) -> Option<GuestPtr<T>>
517    where
518        T: GuestType,
519    {
520        if index < self.len() {
521            Some(
522                self.as_ptr()
523                    .add(index)
524                    .expect("just performed bounds check"),
525            )
526        } else {
527            None
528        }
529    }
530
531    pub fn get_range(&self, r: std::ops::Range<u32>) -> Option<GuestPtr<[T]>>
532    where
533        T: GuestType,
534    {
535        if r.end < r.start {
536            return None;
537        }
538        let range_length = r.end - r.start;
539        if r.start <= self.len() && r.end <= self.len() {
540            Some(
541                self.as_ptr()
542                    .add(r.start)
543                    .expect("just performed bounds check")
544                    .as_array(range_length),
545            )
546        } else {
547            None
548        }
549    }
550}
551
552impl GuestPtr<str> {
553    /// For strings, returns the relative pointer to the base of the string
554    /// allocation.
555    pub fn offset_base(&self) -> u32 {
556        self.pointer.0
557    }
558
559    /// Returns the length, in bytes, of the string.
560    pub fn len(&self) -> u32 {
561        self.pointer.1
562    }
563
564    /// Returns a raw pointer for the underlying slice of bytes that this
565    /// pointer points to.
566    pub fn as_bytes(&self) -> GuestPtr<[u8]> {
567        GuestPtr::new(self.pointer)
568    }
569}
570
571impl<T: ?Sized + Pointee> Clone for GuestPtr<T> {
572    fn clone(&self) -> Self {
573        *self
574    }
575}
576
577impl<T: ?Sized + Pointee> Copy for GuestPtr<T> {}
578
579impl<T: ?Sized + Pointee> fmt::Debug for GuestPtr<T> {
580    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
581        T::debug(self.pointer, f)
582    }
583}
584
585impl<T: ?Sized + Pointee> PartialEq for GuestPtr<T> {
586    fn eq(&self, other: &Self) -> bool {
587        self.pointer == other.pointer
588    }
589}
590
591mod private {
592    pub trait Sealed {}
593    impl<T> Sealed for T {}
594    impl<T> Sealed for [T] {}
595    impl Sealed for str {}
596}
597
598/// Types that can be pointed to by `GuestPtr<T>`.
599///
600/// In essence everything can, and the only special-case is unsized types like
601/// `str` and `[T]` which have special implementations.
602pub trait Pointee: private::Sealed {
603    #[doc(hidden)]
604    type Pointer: Copy + PartialEq;
605    #[doc(hidden)]
606    fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result;
607}
608
609impl<T> Pointee for T {
610    type Pointer = u32;
611    fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result {
612        write!(f, "*guest {pointer:#x}")
613    }
614}
615
616impl<T> Pointee for [T] {
617    type Pointer = (u32, u32);
618    fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result {
619        write!(f, "*guest {:#x}/{}", pointer.0, pointer.1)
620    }
621}
622
623impl Pointee for str {
624    type Pointer = (u32, u32);
625    fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result {
626        <[u8]>::debug(pointer, f)
627    }
628}
629
630pub fn run_in_dummy_executor<F: std::future::Future>(future: F) -> Result<F::Output> {
631    use std::pin::Pin;
632    use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
633
634    let mut f = Pin::from(Box::new(future));
635    let waker = dummy_waker();
636    let mut cx = Context::from_waker(&waker);
637    match f.as_mut().poll(&mut cx) {
638        Poll::Ready(val) => return Ok(val),
639        Poll::Pending => bail!(
640            "Cannot wait on pending future: must enable wiggle \"async\" future and execute on an async Store"
641        ),
642    }
643
644    fn dummy_waker() -> Waker {
645        return unsafe { Waker::from_raw(clone(5 as *const _)) };
646
647        unsafe fn clone(ptr: *const ()) -> RawWaker {
648            assert_eq!(ptr as usize, 5);
649            const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
650            RawWaker::new(ptr, &VTABLE)
651        }
652
653        unsafe fn wake(ptr: *const ()) {
654            assert_eq!(ptr as usize, 5);
655        }
656
657        unsafe fn wake_by_ref(ptr: *const ()) {
658            assert_eq!(ptr as usize, 5);
659        }
660
661        unsafe fn drop(ptr: *const ()) {
662            assert_eq!(ptr as usize, 5);
663        }
664    }
665}