...

Source file src/cuelang.org/go/cue/interpreter/wasm/doc.go

Documentation: cuelang.org/go/cue/interpreter/wasm

     1  // Copyright 2023 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package wasm allows users to write their own functions and make
    16  // them available to CUE via Wasm modules.
    17  //
    18  // To enable Wasm support, pass the result of [New] to
    19  // [cuelang.org/go/cue/cuecontext.New]. Wasm is enabled by default in
    20  // the command line tool.
    21  //
    22  // Wasm is an experimental feature and the interface described in this
    23  // document may change in the future.
    24  //
    25  // # Using Wasm modules in CUE
    26  //
    27  // To utilize Wasm modules, CUE files need to declare their intent by
    28  // specifying a package attribute:
    29  //
    30  //	@extern("wasm")
    31  //	package p
    32  //
    33  // Individual functions can then be imported from Wasm modules using
    34  // a field attribute:
    35  //
    36  //	add: _ @extern("foo.wasm", abi=c, sig="func(int64, int64): int64")
    37  //	mul: _ @extern("foo.wasm", abi=c, sig="func(float64, float64): float64")
    38  //	not: _ @extern("foo.wasm", abi=c, sig="func(bool): bool")
    39  //
    40  // The first attribute argument specifies the file name of the Wasm
    41  // module, which must reside in the same directory as the CUE file
    42  // which uses it. The abi indicates the abstract binary interface (ABI)
    43  // used by the function (see below) while sig indicates the type
    44  // signature of the function. The grammar for sig is:
    45  //
    46  //	list    := expr [ { "," expr } ]
    47  //	func    := "func" "(" [ list ] ")" ":" expr
    48  //
    49  // Where each expr is a valid CUE identifier or selector.
    50  //
    51  // The specific ABI used may restrict the allowable signatures further.
    52  //
    53  // By default, the named Wasm module is searched for a function with
    54  // the same name as the CUE field that is associated with the attribute.
    55  // If you want to import a function under a different name, you can
    56  // specify this in the attribute using an optional name parameter, for
    57  // example:
    58  //
    59  //	isPrime: _ @extern("bar.wasm", abi=c, name=is_prime, sig="func(uint64): bool")
    60  //
    61  // # Runtime requirements for Wasm modules
    62  //
    63  // CUE runs Wasm code in a secure sandbox, which restricts access to
    64  // external resources. Therefore, any Wasm code intended for execution
    65  // in CUE must be self-contained and cannot have external dependencies.
    66  //
    67  // All code exported for use by CUE must be free of observable side
    68  // effects. The result of a function call must depend only on its
    69  // arguments, and no other implicit state. If a function uses global
    70  // state, it must do so only in a way that is undetectable from the
    71  // outside. For example, a function that caches results to speed up
    72  // its future invocations (memoization) is permitted, but a function
    73  // that returns a random number is not.
    74  //
    75  // The CUE runtime may run different function invocations in different
    76  // Wasm runtime instances, so Wasm code must not depend on the existence
    77  // of shared state between different function invocations.
    78  //
    79  // Wasm code must always terminate and return a result.
    80  //
    81  // Failure to provide the above guarantees will break the internal
    82  // logic of CUE and will cause the CUE evaluation to be undefined.
    83  //
    84  // The CUE runtime may try to detect violations of the above rules,
    85  // but it cannot provide any guarantees that violations will be detected.
    86  // It is the responsability of the programmer to comply to the above
    87  // requirements.
    88  //
    89  // # ABI requirements for Wasm modules
    90  //
    91  // Currently only the [System V ABI] (also known as the C ABI) is
    92  // supported. Furthermore, only scalar data types and structs containing
    93  // either scalar types or other structs can be exchanged between CUE
    94  // and Wasm. Scalar means booleans, sized integers, and sized floats.
    95  // The sig field in the attribute refers to these data types by their
    96  // CUE names, such as bool, uint16, float64.
    97  //
    98  // Additionally the Wasm module must export two functions with the
    99  // following C type signature:
   100  //
   101  //	void*	allocate(int n);
   102  //	void	deallocate(void *ptr, int n);
   103  //
   104  // Allocate returns a Wasm pointer to a buffer of size n. Deallocate
   105  // takes a Wasm pointer and the size of the buffer it points to and
   106  // frees it.
   107  //
   108  // # How to compile Rust for use in CUE
   109  //
   110  // To compile Rust code into a Wasm module usable by CUE, make sure
   111  // you have either the wasm32-unknown-unknown or wasm32-wasi targets
   112  // installed:
   113  //
   114  //	rustup target add wasm32-wasi
   115  //
   116  // Note that even with wasm32-wasi, you should assume a [no_std]
   117  // environment. Even though CUE can load [WASI] modules, the loaded
   118  // modules do not currently have access to a WASI environment. This
   119  // might change in the future.
   120  //
   121  // Compile your Rust crate using a cdynlib crate type as your [cargo target]
   122  // targeting the installed Wasm target and make sure the functions you
   123  // are exporting are using the C ABI, like so:
   124  //
   125  //	#[no_mangle]
   126  //	pub extern "C" fn mul(a: f64, b: f64) -> f64 {
   127  //	    a * b
   128  //	}
   129  //
   130  // The following Rust functions can be used to implement allocate and
   131  // deallocate described above:
   132  //
   133  //	#[cfg_attr(all(target_arch = "wasm32"), export_name = "allocate")]
   134  //	#[no_mangle]
   135  //	pub extern "C" fn _allocate(size: u32) -> *mut u8 {
   136  //	    allocate(size as usize)
   137  //	}
   138  //
   139  //	fn allocate(size: usize) -> *mut u8 {
   140  //	    let vec: Vec<MaybeUninit<u8>> = Vec::with_capacity(size);
   141  //
   142  //	    Box::into_raw(vec.into_boxed_slice()) as *mut u8
   143  //	}
   144  //
   145  //	#[cfg_attr(all(target_arch = "wasm32"), export_name = "deallocate")]
   146  //	#[no_mangle]
   147  //	pub unsafe extern "C" fn _deallocate(ptr: u32, size: u32) {
   148  //	    deallocate(ptr as *mut u8, size as usize);
   149  //	}
   150  //
   151  //	unsafe fn deallocate(ptr: *mut u8, size: usize) {
   152  //	    let _ = Vec::from_raw_parts(ptr, 0, size);
   153  //	}
   154  //
   155  // [System V ABI]: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md
   156  // [no_std]: https://docs.rust-embedded.org/book/intro/no-std.html
   157  // [WASI]: https://wasi.dev
   158  // [cargo target]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html
   159  package wasm
   160  

View as plain text