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