1 use crate::{ 2 HeapType, Ref, RefType, Result, Val, ValRaw, ValType, WasmTy, 3 store::{AutoAssertNoGc, StoreOpaque}, 4 }; 5 use core::convert::Infallible; 6 use core::mem::MaybeUninit; 7 8 /// A reference to the abstract `noextern` heap value. 9 /// 10 /// The are no instances of `(ref noextern)`: it is an uninhabited type. 11 /// 12 /// There is precisely one instance of `(ref null noextern)`, aka `nullexternref`: 13 /// the null reference. 14 /// 15 /// This `NoExtern` Rust type's sole purpose is for use with 16 /// [`Func::wrap`][crate::Func::wrap]- and 17 /// [`Func::typed`][crate::Func::typed]-style APIs for statically typing a 18 /// function as taking or returning a `(ref null noextern)` (aka 19 /// `Option<NoExtern>`) which is always `None`. 20 /// 21 /// # Example 22 /// 23 /// ``` 24 /// # use wasmtime::*; 25 /// # fn _foo() -> Result<()> { 26 /// let mut config = Config::new(); 27 /// config.wasm_function_references(true); 28 /// config.wasm_gc(true); 29 /// let engine = Engine::new(&config)?; 30 /// 31 /// let module = Module::new( 32 /// &engine, 33 /// r#" 34 /// (module 35 /// (func (export "f") (param (ref null noextern)) 36 /// ;; If the reference is null, return. 37 /// local.get 0 38 /// ref.is_null noextern 39 /// br_if 0 40 /// 41 /// ;; If the reference was not null (which is impossible) 42 /// ;; then raise a trap. 43 /// unreachable 44 /// ) 45 /// ) 46 /// "#, 47 /// )?; 48 /// 49 /// let mut store = Store::new(&engine, ()); 50 /// let instance = Instance::new(&mut store, &module, &[])?; 51 /// let f = instance.get_func(&mut store, "f").unwrap(); 52 /// 53 /// // We can cast a `(ref null noextern)`-taking function into a typed function that 54 /// // takes an `Option<NoExtern>` via the `Func::typed` method. 55 /// let f = f.typed::<Option<NoExtern>, ()>(&store)?; 56 /// 57 /// // We can call the typed function, passing the null `noextern` reference. 58 /// let result = f.call(&mut store, NoExtern::null()); 59 /// 60 /// // The function should not have trapped, because the reference we gave it was 61 /// // null (as it had to be, since `NoExtern` is uninhabited). 62 /// assert!(result.is_ok()); 63 /// # Ok(()) 64 /// # } 65 /// ``` 66 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 67 pub struct NoExtern { 68 _inner: Infallible, 69 } 70 71 impl NoExtern { 72 /// Get the null `(ref null noextern)` (aka `nullexternref`) reference. 73 #[inline] null() -> Option<Self>74 pub fn null() -> Option<Self> { 75 None 76 } 77 78 /// Get the null `(ref null noextern)` (aka `nullexternref`) reference as a 79 /// [`Ref`]. 80 #[inline] null_ref() -> Ref81 pub fn null_ref() -> Ref { 82 Ref::Extern(None) 83 } 84 85 /// Get the null `(ref null noextern)` (aka `nullexternref`) reference as a 86 /// [`Val`]. 87 #[inline] null_val() -> Val88 pub fn null_val() -> Val { 89 Val::ExternRef(None) 90 } 91 } 92 93 unsafe impl WasmTy for NoExtern { 94 #[inline] valtype() -> ValType95 fn valtype() -> ValType { 96 ValType::Ref(RefType::new(false, HeapType::NoExtern)) 97 } 98 99 #[inline] compatible_with_store(&self, _store: &StoreOpaque) -> bool100 fn compatible_with_store(&self, _store: &StoreOpaque) -> bool { 101 match self._inner {} 102 } 103 104 #[inline] dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &HeapType) -> Result<()>105 fn dynamic_concrete_type_check(&self, _: &StoreOpaque, _: bool, _: &HeapType) -> Result<()> { 106 match self._inner {} 107 } 108 109 #[inline] is_vmgcref_and_points_to_object(&self) -> bool110 fn is_vmgcref_and_points_to_object(&self) -> bool { 111 match self._inner {} 112 } 113 store(self, _store: &mut AutoAssertNoGc<'_>, _ptr: &mut MaybeUninit<ValRaw>) -> Result<()>114 fn store(self, _store: &mut AutoAssertNoGc<'_>, _ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 115 match self._inner {} 116 } 117 load(_store: &mut AutoAssertNoGc<'_>, _ptr: &ValRaw) -> Self118 unsafe fn load(_store: &mut AutoAssertNoGc<'_>, _ptr: &ValRaw) -> Self { 119 unreachable!("NoExtern is uninhabited") 120 } 121 } 122 123 unsafe impl WasmTy for Option<NoExtern> { 124 #[inline] valtype() -> ValType125 fn valtype() -> ValType { 126 ValType::Ref(RefType::new(true, HeapType::NoExtern)) 127 } 128 129 #[inline] compatible_with_store(&self, _store: &StoreOpaque) -> bool130 fn compatible_with_store(&self, _store: &StoreOpaque) -> bool { 131 true 132 } 133 134 #[inline] dynamic_concrete_type_check( &self, _store: &StoreOpaque, _nullable: bool, _ty: &HeapType, ) -> Result<()>135 fn dynamic_concrete_type_check( 136 &self, 137 _store: &StoreOpaque, 138 _nullable: bool, 139 _ty: &HeapType, 140 ) -> Result<()> { 141 unreachable!() 142 } 143 144 #[inline] store(self, _store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()>145 fn store(self, _store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> { 146 ptr.write(ValRaw::externref(0)); 147 Ok(()) 148 } 149 150 #[inline] load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self151 unsafe fn load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self { 152 debug_assert_eq!(ptr.get_externref(), 0); 153 None 154 } 155 } 156