├── .gitattributes ├── .github └── workflows │ ├── push.yml │ └── release-build.yml ├── .gitignore ├── Bin ├── copy-libs.sh └── merge-libs.sh ├── LICENSE ├── Lib ├── .gitignore ├── Makefile ├── include │ ├── chezscheme-arm64-ios.h │ ├── chezscheme-arm64-iphonesimulator.h │ ├── chezscheme-arm64-macos.h │ ├── chezscheme-x86_64-macos.h │ ├── module.modulemap │ ├── racket.h │ ├── racketcs.h │ └── racketcsboot.h ├── libracketcs-arm64-ios.a ├── libracketcs-arm64-iphonesimulator.a ├── libracketcs-arm64-macos.a └── libracketcs-x86_64-macos.a ├── Makefile ├── Package.swift ├── README.md ├── Racket ├── noise-serde-doc │ ├── info.rkt │ └── noise-manual.scrbl ├── noise-serde-lib │ ├── .gitignore │ ├── backend.rkt │ ├── codegen.rkt │ ├── info.rkt │ ├── private │ │ ├── backend.rkt │ │ ├── callout.rkt │ │ ├── common.rkt │ │ ├── debug.rkt │ │ ├── sequencer.rkt │ │ └── serde.rkt │ ├── serde.rkt │ └── unsafe │ │ └── callout.rkt └── noise-serde-lint-lib │ ├── examples │ ├── basic.rkt │ └── info.rkt │ ├── info.rkt │ └── review.rkt ├── Sources ├── Noise │ └── Racket.swift ├── NoiseBackend │ ├── Backend.swift │ ├── Callout.swift │ └── Future.swift ├── NoiseBoot_iOS │ ├── NoiseBoot.swift │ └── boot │ │ └── arm64-ios │ │ ├── petite.boot │ │ ├── racket.boot │ │ └── scheme.boot ├── NoiseBoot_macOS │ ├── NoiseBoot.swift │ └── boot │ │ ├── arm64-macos │ │ ├── petite.boot │ │ ├── racket.boot │ │ └── scheme.boot │ │ └── x86_64-macos │ │ ├── petite.boot │ │ ├── racket.boot │ │ └── scheme.boot └── NoiseSerde │ ├── DataInputPort.swift │ ├── DataOutputPort.swift │ ├── FileHandleInputPort.swift │ ├── FileHandleOutputPort.swift │ ├── Port.swift │ └── Serde.swift ├── Template ├── BackendExtensions.swift ├── Entitlements │ ├── 00-Application.entitlements │ └── 01-dylib.entitlements ├── Makefile ├── README.md └── bin │ ├── pbracket │ ├── pbraco │ └── sign-dylibs └── Tests └── NoiseTest ├── FutureTest.swift ├── Modules ├── .gitignore ├── Makefile ├── bytes.rkt ├── callout.rkt ├── cookie ├── fib.rkt ├── http.rkt └── loud.rkt ├── RacketTest.swift └── SerdeTest.swift /.gitattributes: -------------------------------------------------------------------------------- 1 | *.a filter=lfs diff=lfs merge=lfs -text 2 | *.boot filter=lfs diff=lfs merge=lfs -text 3 | *.zo filter=lfs diff=lfs merge=lfs -text 4 | -------------------------------------------------------------------------------- /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push] 3 | jobs: 4 | build: 5 | runs-on: macos-15 6 | name: Build & Test 7 | steps: 8 | - name: Checkout 9 | uses: actions/checkout@master 10 | 11 | - name: Check Swift Version 12 | run: swift --version 13 | 14 | - name: Setup Racket 15 | uses: Bogdanp/setup-racket@v1.13 16 | with: 17 | variant: 'CS' 18 | version: 'current' 19 | packages: 'http-easy-lib' 20 | 21 | - name: Build LFS file list 22 | run: git lfs ls-files -l | cut -d ' ' -f1 | sort > .lfs-ids 23 | 24 | - name: Cache LFS files 25 | uses: actions/cache@v4 26 | with: 27 | path: .git/lfs 28 | key: lfs-${{ hashFiles('.lfs-ids') }} 29 | 30 | - name: Pull LFS 31 | run: git lfs pull 32 | 33 | - name: Install noise-serde-lib 34 | run: 35 | pushd Racket && raco pkg install --auto noise-serde-lib/ noise-serde-doc/ 36 | 37 | - name: Build & Test 38 | run: make && swift build && swift test 39 | -------------------------------------------------------------------------------- /.github/workflows/release-build.yml: -------------------------------------------------------------------------------- 1 | name: Build Release 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | branch: 6 | description: "Target Branch" 7 | required: false 8 | type: string 9 | version: 10 | description: "Racket Version" 11 | required: true 12 | type: string 13 | jobs: 14 | build: 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | target-os: ["iOS", "iPhoneSimulator", "macOS"] 19 | target-arch: ["aarch64", "x86_64"] 20 | builder: ["macos-13", "macos-14"] 21 | exclude: 22 | - target-os: iOS 23 | builder: macos-13 24 | - target-os: iOS 25 | target-arch: x86_64 26 | - target-os: iPhoneSimulator 27 | builder: macos-13 28 | - target-os: iPhoneSimulator 29 | target-arch: x86_64 30 | - builder: macos-14 31 | target-arch: x86_64 32 | - builder: macos-13 33 | target-arch: aarch64 34 | runs-on: ${{ matrix.builder }} 35 | name: "Build racket-${{ inputs.version || '8.17' }}-${{ matrix.target-arch}}-${{ matrix.target-os }}" 36 | steps: 37 | - name: Checkout 38 | uses: actions/checkout@master 39 | 40 | - name: Check Swift Version 41 | run: swift --version 42 | 43 | - name: Install Host Racket 44 | if: ${{ startsWith(matrix.target-os, 'i') }} 45 | uses: Bogdanp/setup-racket@v1.13 46 | with: 47 | variant: "CS" 48 | version: "current" 49 | 50 | - name: Build LibFFI for iOS 51 | if: ${{ matrix.target-os == 'iOS' }} 52 | run: | 53 | set -euxo pipefail 54 | brew install automake libtool 55 | git clone https://github.com/libffi/libffi 56 | cd libffi 57 | git checkout v3.4.8 58 | ./autogen.sh 59 | python generate-darwin-source-and-headers.py --only-ios 60 | xcodebuild \ 61 | -configuration release \ 62 | -target libffi-iOS \ 63 | -scheme libffi-iOS \ 64 | -sdk "$(xcode-select -p)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk" \ 65 | -derivedDataPath dist \ 66 | IPHONEOS_DEPLOYMENT_TARGET=12 67 | 68 | - name: Build LibFFI for iPhoneSimulator 69 | if: ${{ matrix.target-os == 'iPhoneSimulator' }} 70 | run: | 71 | set -euxo pipefail 72 | brew install automake libtool 73 | git clone https://github.com/libffi/libffi 74 | cd libffi 75 | git checkout v3.4.8 76 | curl https://gist.githubusercontent.com/Bogdanp/ea344f45015ee32576639dc402aeca11/raw/f075ec2adb655789019fdd5a94c521ea2579552d/0001-add-tramp.c-to-x86_64-for-iPhoneSimulator.patch | \ 77 | git apply - 78 | ./autogen.sh 79 | python generate-darwin-source-and-headers.py --only-ios 80 | xcodebuild \ 81 | -configuration release \ 82 | -target libffi-iOS \ 83 | -scheme libffi-iOS \ 84 | -sdk "$(xcode-select -p)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk" \ 85 | -derivedDataPath dist 86 | 87 | - name: Download and Untar Racket 88 | run: | 89 | curl -L -o racket.tar.gz https://download.racket-lang.org/installers/${{ inputs.version || '8.17' }}/racket-minimal-${{ inputs.version || '8.17' }}-src-builtpkgs.tgz 90 | tar xzf racket.tar.gz 91 | 92 | - name: Build Racket for macOS 93 | if: ${{ matrix.target-os == 'macOS' }} 94 | run: | 95 | pushd racket-${{ inputs.version || '8.17' }} 96 | pushd src 97 | export LD_LIBRARY_PATH="$(brew --prefix)/lib:$LD_LIBRARY_PATH" 98 | export DYLD_LIBRARY_PATH="$(brew --prefix)/lib:$DYLD_LIBRARY_PATH" 99 | export MACOSX_DEPLOYMENT_TARGET=12.0 100 | export PKG_CONFIG_PATH=$(pwd) 101 | ./configure \ 102 | --enable-compressboot \ 103 | --enable-strip 104 | make 105 | make install 106 | 107 | - name: Build Racket for iOS 108 | if: ${{ matrix.target-os == 'iOS' }} 109 | run: | 110 | pushd racket-${{ inputs.version || '8.17' }} 111 | pushd src 112 | cat >libffi.pc <libffi.pc < 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /Lib/.gitignore: -------------------------------------------------------------------------------- 1 | libracketcs-universal-macos.a 2 | -------------------------------------------------------------------------------- /Lib/Makefile: -------------------------------------------------------------------------------- 1 | libracketcs-universal-macos.a: libracketcs-arm64-macos.a libracketcs-x86_64-macos.a 2 | lipo -create -output $@ libracketcs-arm64-macos.a libracketcs-x86_64-macos.a 3 | 4 | .PHONY: clean 5 | clean: 6 | rm libracketcs-universal-*.a 7 | -------------------------------------------------------------------------------- /Lib/include/chezscheme-arm64-ios.h: -------------------------------------------------------------------------------- 1 | /* scheme.h for Chez Scheme Version 10.2.0-pre-release.2 (tpb64l) */ 2 | 3 | /* Do not edit this file. It is automatically generated and */ 4 | /* specifically tailored to the version of Chez Scheme named */ 5 | /* above. Always be certain that you have the correct scheme.h */ 6 | /* for the version of Chez Scheme you are using. */ 7 | 8 | /* Warning: Some macros may evaluate arguments more than once. */ 9 | 10 | #if !defined(_LARGEFILE64_SOURCE) && !defined(FEATURE_WINDOWS) 11 | # define _LARGEFILE64_SOURCE 12 | #endif 13 | #include 14 | 15 | /* Specify declaration of exports. */ 16 | #ifdef _WIN32 17 | # if __cplusplus 18 | # ifdef SCHEME_IMPORT 19 | # define EXPORT extern "C" __declspec (dllimport) 20 | # elif SCHEME_STATIC 21 | # define EXPORT extern "C" 22 | # else 23 | # define EXPORT extern "C" __declspec (dllexport) 24 | # endif 25 | # else 26 | # ifdef SCHEME_IMPORT 27 | # define EXPORT extern __declspec (dllimport) 28 | # elif SCHEME_STATIC 29 | # define EXPORT extern 30 | # else 31 | # define EXPORT extern __declspec (dllexport) 32 | # endif 33 | # endif 34 | #else 35 | # if __cplusplus 36 | # define EXPORT extern "C" 37 | # else 38 | # define EXPORT extern 39 | # endif 40 | #endif 41 | 42 | /* Chez Scheme Version and machine type */ 43 | #define VERSION "10.2.0-pre-release.2" 44 | #define MACHINE_TYPE "tpb64l" 45 | 46 | /* Integer typedefs */ 47 | typedef int32_t Sint32_t; 48 | typedef uint32_t Suint32_t; 49 | typedef int64_t Sint64_t; 50 | typedef uint64_t Suint64_t; 51 | 52 | /* All Scheme objects are of type ptr. Type iptr and */ 53 | /* uptr are signed and unsigned ints of the same size */ 54 | /* as a ptr */ 55 | typedef uint64_t ptr; 56 | typedef int64_t iptr; 57 | typedef uint64_t uptr; 58 | typedef ptr xptr; 59 | 60 | /* The `uptr` and `ptr` types are the same width, but `ptr` */ 61 | /* can be either an integer type or a pointer type; it may */ 62 | /* be larger than a pointer type. */ 63 | /* Use `TO_VOIDP` to get from the `uptr`/`ptr` world to the */ 64 | /* C pointer worlds, and use `TO_PTR` to go the other way. */ 65 | #ifdef PORTABLE_BYTECODE 66 | # define TO_VOIDP(p) ((void *)(intptr_t)(p)) 67 | # define TO_PTR(p) ((ptr)(intptr_t)(p)) 68 | #else 69 | # define TO_VOIDP(p) ((void *)(p)) 70 | # define TO_PTR(p) ((ptr)(p)) 71 | #endif 72 | 73 | /* String elements are 32-bit tagged char objects */ 74 | typedef uint32_t string_char; 75 | 76 | /* Bytevector elements are 8-bit unsigned "octets" */ 77 | typedef unsigned char octet; 78 | 79 | /* Type predicates */ 80 | #define Sfixnump(x) (((uptr)(x)&0x7)==0x0) 81 | #define Scharp(x) (((uptr)(x)&0xFF)==0x16) 82 | #define Snullp(x) ((uptr)(x)==0x26) 83 | #define Seof_objectp(x) ((uptr)(x)==0x36) 84 | #define Sbwp_objectp(x) ((uptr)(x)==0x4E) 85 | #define Sbooleanp(x) (((uptr)(x)&0xF7)==0x6) 86 | #define Spairp(x) (((uptr)(x)&0x7)==0x1) 87 | #define Ssymbolp(x) (((uptr)(x)&0x7)==0x3) 88 | #define Sprocedurep(x) (((uptr)(x)&0x7)==0x5) 89 | #define Sflonump(x) (((uptr)(x)&0x7)==0x2) 90 | #define Svectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 91 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x0)) 92 | #define Sfxvectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 93 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xF)==0x3)) 94 | #define Sflvectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 95 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xF)==0xB)) 96 | #define Sbytevectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 97 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3)==0x1)) 98 | #define Sstringp(x) ((((uptr)(x)&0x7)==0x7) &&\ 99 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x2)) 100 | #define Sstencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 101 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3F)==0xE)) 102 | #define Ssystem_stencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 103 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3F)==0x2E)) 104 | #define Sany_stencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 105 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1F)==0xE)) 106 | #define Sbignump(x) ((((uptr)(x)&0x7)==0x7) &&\ 107 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1F)==0x6)) 108 | #define Sboxp(x) ((((uptr)(x)&0x7)==0x7) &&\ 109 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xFF)==0x1E)) 110 | #define Sinexactnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 111 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x36)) 112 | #define Sexactnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 113 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x56)) 114 | #define Sratnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 115 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x16)) 116 | #define Sinputportp(x) ((((uptr)(x)&0x7)==0x7) &&\ 117 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1FF)==0x1DE)) 118 | #define Soutputportp(x) ((((uptr)(x)&0x7)==0x7) &&\ 119 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x2FF)==0x2DE)) 120 | #define Srecordp(x) ((((uptr)(x)&0x7)==0x7) &&\ 121 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x7)) 122 | 123 | /* Accessors */ 124 | #define Sfixnum_value(x) ((iptr)(x)/8) 125 | #define Schar_value(x) ((string_char)((uptr)(x)>>8)) 126 | #define Sboolean_value(x) ((x) != Sfalse) 127 | #define Scar(x) (*((ptr *)TO_VOIDP((uptr)(x)+7))) 128 | #define Scdr(x) (*((ptr *)TO_VOIDP((uptr)(x)+15))) 129 | #define Sflonum_value(x) (*((double *)TO_VOIDP((uptr)(x)+6))) 130 | #define Svector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 131 | #define Svector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 132 | #define Sfxvector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 133 | #define Sfxvector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 134 | #define Sflvector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 135 | #define Sflvector_ref(x,i) (((double *)TO_VOIDP((uptr)(x)+9))[i]) 136 | #define Sbytevector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>3)) 137 | #define Sbytevector_u8_ref(x,i) (((octet *)TO_VOIDP((uptr)(x)+9))[i]) 138 | /* Warning: Sbytevector_data(x) returns a pointer into x. */ 139 | #define Sbytevector_data(x) &Sbytevector_u8_ref(x,0) 140 | #define Sstring_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 141 | #define Sstring_ref(x,i) Schar_value(((string_char *)TO_VOIDP((uptr)(x)+9))[i]) 142 | #define Sunbox(x) (*((ptr *)TO_VOIDP((uptr)(x)+9))) 143 | #define Sstencil_vector_length(x) Spopcount(((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1))))>>6) 144 | #define Sstencil_vector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 145 | EXPORT iptr Sinteger_value(ptr); 146 | #define Sunsigned_value(x) (uptr)Sinteger_value(x) 147 | EXPORT Sint32_t Sinteger32_value(ptr); 148 | #define Sunsigned32_value(x) (Suint32_t)Sinteger32_value(x) 149 | EXPORT Sint64_t Sinteger64_value(ptr); 150 | EXPORT int Stry_integer_value(ptr, iptr*, const char**); 151 | EXPORT int Stry_integer32_value(ptr, Sint32_t*, const char**); 152 | EXPORT int Stry_integer64_value(ptr, Sint64_t*, const char**); 153 | #define Sunsigned64_value(x) (Suint64_t)Sinteger64_value(x) 154 | EXPORT int Stry_unsigned_value(ptr, uptr*, const char**); 155 | EXPORT int Stry_unsigned32_value(ptr, Suint32_t*, const char**); 156 | EXPORT int Stry_unsigned64_value(ptr, Suint64_t*, const char**); 157 | 158 | /* Mutators */ 159 | EXPORT void Sset_box(ptr, ptr); 160 | EXPORT void Sset_car(ptr, ptr); 161 | EXPORT void Sset_cdr(ptr, ptr); 162 | #define Sstring_set(x,i,c) ((void)((((string_char *)TO_VOIDP((uptr)(x)+9))[i]) = (string_char)(uptr)Schar(c))) 163 | #define Sfxvector_set(x,i,n) ((void)(Sfxvector_ref(x,i) = (n))) 164 | #define Sflvector_set(x,i,n) ((void)(Sflvector_ref(x,i) = (n))) 165 | #define Sbytevector_u8_set(x,i,n) ((void)(Sbytevector_u8_ref(x,i) = (n))) 166 | EXPORT void Svector_set(ptr, iptr, ptr); 167 | 168 | /* Constructors */ 169 | #define Sfixnum(x) ((ptr)(uptr)((x)*8)) 170 | #define Schar(x) ((ptr)(uptr)((x)<<8|0x16)) 171 | #define Snil ((ptr)0x26) 172 | #define Strue ((ptr)0xE) 173 | #define Sfalse ((ptr)0x6) 174 | #define Sboolean(x) ((x)?Strue:Sfalse) 175 | #define Sbwp_object ((ptr)0x4E) 176 | #define Seof_object ((ptr)0x36) 177 | #define Svoid ((ptr)0x2E) 178 | EXPORT ptr Scons(ptr, ptr); 179 | EXPORT ptr Sstring_to_symbol(const char *); 180 | EXPORT ptr Ssymbol_to_string(ptr); 181 | EXPORT ptr Sflonum(double); 182 | EXPORT ptr Smake_vector(iptr, ptr); 183 | EXPORT ptr Smake_fxvector(iptr, ptr); 184 | EXPORT ptr Smake_flvector(iptr, double); 185 | EXPORT ptr Smake_bytevector(iptr, int); 186 | EXPORT ptr Smake_string(iptr, int); 187 | EXPORT ptr Smake_uninitialized_string(iptr); 188 | EXPORT ptr Sstring(const char *); 189 | EXPORT ptr Sstring_of_length(const char *, iptr); 190 | EXPORT ptr Sstring_utf8(const char*, iptr); 191 | EXPORT ptr Sbox(ptr); 192 | EXPORT ptr Sinteger(iptr); 193 | EXPORT ptr Sunsigned(uptr); 194 | EXPORT ptr Sinteger32(Sint32_t); 195 | EXPORT ptr Sunsigned32(Suint32_t); 196 | EXPORT ptr Sinteger64(Sint64_t); 197 | EXPORT ptr Sunsigned64(Suint64_t); 198 | 199 | /* Records */ 200 | #define Srecord_uniform_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 201 | EXPORT ptr Srecord_type(ptr); 202 | EXPORT ptr Srecord_type_parent(ptr); 203 | EXPORT int Srecord_type_uniformp(ptr); 204 | EXPORT uptr Srecord_type_size(ptr); 205 | 206 | /* Miscellaneous */ 207 | EXPORT ptr Stop_level_value(ptr); 208 | EXPORT void Sset_top_level_value(ptr, ptr); 209 | EXPORT void Slock_object(ptr); 210 | EXPORT void Sunlock_object(ptr); 211 | EXPORT int Slocked_objectp(ptr); 212 | EXPORT void Sforeign_symbol(const char *, void *); 213 | EXPORT void Sregister_symbol(const char *, void *); 214 | 215 | /* Support for calls into Scheme */ 216 | EXPORT ptr Scall0(ptr); 217 | EXPORT ptr Scall1(ptr, ptr); 218 | EXPORT ptr Scall2(ptr, ptr, ptr); 219 | EXPORT ptr Scall3(ptr, ptr, ptr, ptr); 220 | EXPORT void Sinitframe(iptr); 221 | EXPORT void Sput_arg(iptr, ptr); 222 | EXPORT ptr Scall(ptr, iptr); 223 | #define Sforeign_callable_entry_point(x) TO_PTR(Svector_ref(x, 2)) 224 | EXPORT ptr Sforeign_callable_code_object(void*); 225 | 226 | /* Customization support. */ 227 | EXPORT const char * Skernel_version(void); 228 | EXPORT void Sretain_static_relocation(void); 229 | EXPORT void Sset_verbose(int); 230 | EXPORT void Sscheme_init(void (*)(void)); 231 | EXPORT void Sregister_boot_file(const char *); 232 | EXPORT void Sregister_boot_executable_relative_file(const char *, const char *); 233 | EXPORT void Sregister_boot_relative_file(const char *); 234 | EXPORT void Sregister_boot_file_fd(const char *, int); 235 | EXPORT void Sregister_boot_file_fd_region(const char *, int, iptr, iptr, int); 236 | EXPORT void Sregister_boot_file_bytes(const char *, void *, iptr); 237 | EXPORT void Sregister_heap_file(const char *); 238 | EXPORT void Scompact_heap(void); 239 | EXPORT void Ssave_heap(const char *, int); 240 | EXPORT void Sbuild_heap(const char *, void (*)(void)); 241 | EXPORT void Senable_expeditor(const char *); 242 | EXPORT int Sscheme_start(int, const char *[]); 243 | EXPORT int Sscheme_script(const char *, int, const char *[]); 244 | EXPORT int Sscheme_program(const char *, int, const char *[]); 245 | EXPORT void Sscheme_deinit(void); 246 | EXPORT void Sscheme_register_signal_registerer(void (*f)(int)); 247 | EXPORT void Sregister_pbchunks(void **, int, int); 248 | 249 | /* Thread support. */ 250 | EXPORT int Sactivate_thread(void); 251 | EXPORT void Sdeactivate_thread(void); 252 | EXPORT int Sdestroy_thread(void); 253 | 254 | /* Windows support. */ 255 | #if defined(FEATURE_WINDOWS) 256 | #include 257 | EXPORT char * Sgetenv(const char *); 258 | EXPORT wchar_t * Sutf8_to_wide(const char *); 259 | EXPORT char * Swide_to_utf8(const wchar_t *); 260 | #endif 261 | 262 | /* Features. */ 263 | #define FEATURE_ICONV 264 | #define FEATURE_EXPEDITOR 265 | #define FEATURE_PTHREADS 266 | #define FEATURE_PBCHUNK 267 | 268 | /* C call prototypes. */ 269 | #include 270 | typedef void (*pb_void_t)(); 271 | typedef void (*pb_void_uptr_t)(uptr); 272 | typedef void (*pb_void_int32_t)(int32_t); 273 | typedef void (*pb_void_uint32_t)(uint32_t); 274 | typedef void (*pb_void_voids_t)(void*); 275 | typedef void (*pb_void_uptr_uint32_t)(uptr, uint32_t); 276 | typedef void (*pb_void_int32_uptr_t)(int32_t, uptr); 277 | typedef void (*pb_void_int32_int32_t)(int32_t, int32_t); 278 | typedef void (*pb_void_uint32_uint32_t)(uint32_t, uint32_t); 279 | typedef void (*pb_void_uptr_uptr_t)(uptr, uptr); 280 | typedef void (*pb_void_int32_voids_t)(int32_t, void*); 281 | typedef void (*pb_void_uptr_voids_t)(uptr, void*); 282 | typedef void (*pb_void_voids_voids_t)(void*, void*); 283 | typedef void (*pb_void_uptr_uptr_uptr_t)(uptr, uptr, uptr); 284 | typedef void (*pb_void_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr, uptr); 285 | typedef int32_t (*pb_int32_t)(); 286 | typedef int32_t (*pb_int32_int32_t)(int32_t); 287 | typedef int32_t (*pb_int32_uptr_t)(uptr); 288 | typedef int32_t (*pb_int32_voids_t)(void*); 289 | typedef int32_t (*pb_int32_int32_uptr_t)(int32_t, uptr); 290 | typedef int32_t (*pb_int32_uptr_int32_t)(uptr, int32_t); 291 | typedef int32_t (*pb_int32_uptr_uptr_t)(uptr, uptr); 292 | typedef int32_t (*pb_int32_int32_int32_t)(int32_t, int32_t); 293 | typedef int32_t (*pb_int32_int32_voids_t)(int32_t, void*); 294 | typedef int32_t (*pb_int32_voids_int32_t)(void*, int32_t); 295 | typedef int32_t (*pb_int32_double_double_double_double_double_double_t)(double, double, double, double, double, double); 296 | typedef int32_t (*pb_int32_voids_voids_voids_voids_uptr_t)(void*, void*, void*, void*, uptr); 297 | typedef uint32_t (*pb_uint32_t)(); 298 | typedef double (*pb_double_double_t)(double); 299 | typedef double (*pb_double_uptr_t)(uptr); 300 | typedef double (*pb_double_double_double_t)(double, double); 301 | typedef int32_t (*pb_int32_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr, uptr); 302 | typedef int32_t (*pb_int32_uptr_uptr_uptr_t)(uptr, uptr, uptr); 303 | typedef uptr (*pb_uptr_t)(); 304 | typedef uptr (*pb_uptr_uptr_t)(uptr); 305 | typedef uptr (*pb_uptr_int32_t)(int32_t); 306 | typedef uptr (*pb_uptr_voids_t)(void*); 307 | typedef uptr (*pb_uptr_uptr_uptr_t)(uptr, uptr); 308 | typedef uptr (*pb_uptr_uptr_int32_t)(uptr, int32_t); 309 | typedef uptr (*pb_uptr_int32_uptr_t)(int32_t, uptr); 310 | typedef uptr (*pb_uptr_uptr_int64_t)(uptr, int64_t); 311 | typedef uptr (*pb_uptr_uptr_voids_t)(uptr, void*); 312 | typedef uptr (*pb_uptr_voids_uptr_t)(void*, uptr); 313 | typedef uptr (*pb_uptr_voids_int32_t)(void*, int32_t); 314 | typedef uptr (*pb_uptr_voids_voids_t)(void*, void*); 315 | typedef uptr (*pb_uptr_uptr_int32_int32_t)(uptr, int32_t, int32_t); 316 | typedef uptr (*pb_uptr_uptr_uptr_int32_t)(uptr, uptr, int32_t); 317 | typedef uptr (*pb_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr); 318 | typedef uptr (*pb_uptr_int32_int32_uptr_t)(int32_t, int32_t, uptr); 319 | typedef uptr (*pb_uptr_voids_int32_int32_t)(void*, int32_t, int32_t); 320 | typedef uptr (*pb_uptr_voids_uptr_uptr_t)(void*, uptr, uptr); 321 | typedef uptr (*pb_uptr_int32_uptr_uptr_uptr_t)(int32_t, uptr, uptr, uptr); 322 | typedef uptr (*pb_uptr_int32_int32_uptr_uptr_t)(int32_t, int32_t, uptr, uptr); 323 | typedef uptr (*pb_uptr_int32_voids_uptr_uptr_t)(int32_t, void*, uptr, uptr); 324 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr); 325 | typedef uptr (*pb_uptr_int32_int32_int32_uptr_t)(int32_t, int32_t, int32_t, uptr); 326 | typedef uptr (*pb_uptr_uptr_voids_uptr_uptr_t)(uptr, void*, uptr, uptr); 327 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_int32_t)(uptr, uptr, uptr, uptr, int32_t); 328 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr, uptr); 329 | typedef uptr (*pb_uptr_voids_voids_voids_voids_uptr_t)(void*, void*, void*, void*, uptr); 330 | typedef uptr (*pb_uptr_uptr_int32_uptr_uptr_uptr_uptr_t)(uptr, int32_t, uptr, uptr, uptr, uptr); 331 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr, uptr, uptr); 332 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_uptr_uptr_int32_t)(uptr, uptr, uptr, uptr, uptr, uptr, int32_t); 333 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr, uptr, uptr, uptr); 334 | typedef uptr (*pb_uptr_double_double_double_double_double_double_t)(double, double, double, double, double, double); 335 | typedef void* (*pb_voids_t)(); 336 | typedef void* (*pb_voids_uptr_t)(uptr); 337 | 338 | /* Locking macros. */ 339 | #define INITLOCK(addr) (*((long *) addr) = 0) 340 | #define UNLOCK(addr) (*((long *) addr) = 0) 341 | #define SPINLOCK(addr) S_pb_spinlock(addr) 342 | #define LOCKED_INCR(addr, res) (res = S_pb_locked_adjust(addr, 1)) 343 | #define LOCKED_DECR(addr, res) (res = S_pb_locked_adjust(addr, -1)) 344 | EXPORT void S_pb_spinlock(void*); 345 | EXPORT int S_pb_locked_adjust(void*, int); 346 | -------------------------------------------------------------------------------- /Lib/include/chezscheme-arm64-iphonesimulator.h: -------------------------------------------------------------------------------- 1 | /* scheme.h for Chez Scheme Version 10.2.0-pre-release.2 (tpb64l) */ 2 | 3 | /* Do not edit this file. It is automatically generated and */ 4 | /* specifically tailored to the version of Chez Scheme named */ 5 | /* above. Always be certain that you have the correct scheme.h */ 6 | /* for the version of Chez Scheme you are using. */ 7 | 8 | /* Warning: Some macros may evaluate arguments more than once. */ 9 | 10 | #if !defined(_LARGEFILE64_SOURCE) && !defined(FEATURE_WINDOWS) 11 | # define _LARGEFILE64_SOURCE 12 | #endif 13 | #include 14 | 15 | /* Specify declaration of exports. */ 16 | #ifdef _WIN32 17 | # if __cplusplus 18 | # ifdef SCHEME_IMPORT 19 | # define EXPORT extern "C" __declspec (dllimport) 20 | # elif SCHEME_STATIC 21 | # define EXPORT extern "C" 22 | # else 23 | # define EXPORT extern "C" __declspec (dllexport) 24 | # endif 25 | # else 26 | # ifdef SCHEME_IMPORT 27 | # define EXPORT extern __declspec (dllimport) 28 | # elif SCHEME_STATIC 29 | # define EXPORT extern 30 | # else 31 | # define EXPORT extern __declspec (dllexport) 32 | # endif 33 | # endif 34 | #else 35 | # if __cplusplus 36 | # define EXPORT extern "C" 37 | # else 38 | # define EXPORT extern 39 | # endif 40 | #endif 41 | 42 | /* Chez Scheme Version and machine type */ 43 | #define VERSION "10.2.0-pre-release.2" 44 | #define MACHINE_TYPE "tpb64l" 45 | 46 | /* Integer typedefs */ 47 | typedef int32_t Sint32_t; 48 | typedef uint32_t Suint32_t; 49 | typedef int64_t Sint64_t; 50 | typedef uint64_t Suint64_t; 51 | 52 | /* All Scheme objects are of type ptr. Type iptr and */ 53 | /* uptr are signed and unsigned ints of the same size */ 54 | /* as a ptr */ 55 | typedef uint64_t ptr; 56 | typedef int64_t iptr; 57 | typedef uint64_t uptr; 58 | typedef ptr xptr; 59 | 60 | /* The `uptr` and `ptr` types are the same width, but `ptr` */ 61 | /* can be either an integer type or a pointer type; it may */ 62 | /* be larger than a pointer type. */ 63 | /* Use `TO_VOIDP` to get from the `uptr`/`ptr` world to the */ 64 | /* C pointer worlds, and use `TO_PTR` to go the other way. */ 65 | #ifdef PORTABLE_BYTECODE 66 | # define TO_VOIDP(p) ((void *)(intptr_t)(p)) 67 | # define TO_PTR(p) ((ptr)(intptr_t)(p)) 68 | #else 69 | # define TO_VOIDP(p) ((void *)(p)) 70 | # define TO_PTR(p) ((ptr)(p)) 71 | #endif 72 | 73 | /* String elements are 32-bit tagged char objects */ 74 | typedef uint32_t string_char; 75 | 76 | /* Bytevector elements are 8-bit unsigned "octets" */ 77 | typedef unsigned char octet; 78 | 79 | /* Type predicates */ 80 | #define Sfixnump(x) (((uptr)(x)&0x7)==0x0) 81 | #define Scharp(x) (((uptr)(x)&0xFF)==0x16) 82 | #define Snullp(x) ((uptr)(x)==0x26) 83 | #define Seof_objectp(x) ((uptr)(x)==0x36) 84 | #define Sbwp_objectp(x) ((uptr)(x)==0x4E) 85 | #define Sbooleanp(x) (((uptr)(x)&0xF7)==0x6) 86 | #define Spairp(x) (((uptr)(x)&0x7)==0x1) 87 | #define Ssymbolp(x) (((uptr)(x)&0x7)==0x3) 88 | #define Sprocedurep(x) (((uptr)(x)&0x7)==0x5) 89 | #define Sflonump(x) (((uptr)(x)&0x7)==0x2) 90 | #define Svectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 91 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x0)) 92 | #define Sfxvectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 93 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xF)==0x3)) 94 | #define Sflvectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 95 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xF)==0xB)) 96 | #define Sbytevectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 97 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3)==0x1)) 98 | #define Sstringp(x) ((((uptr)(x)&0x7)==0x7) &&\ 99 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x2)) 100 | #define Sstencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 101 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3F)==0xE)) 102 | #define Ssystem_stencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 103 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3F)==0x2E)) 104 | #define Sany_stencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 105 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1F)==0xE)) 106 | #define Sbignump(x) ((((uptr)(x)&0x7)==0x7) &&\ 107 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1F)==0x6)) 108 | #define Sboxp(x) ((((uptr)(x)&0x7)==0x7) &&\ 109 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xFF)==0x1E)) 110 | #define Sinexactnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 111 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x36)) 112 | #define Sexactnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 113 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x56)) 114 | #define Sratnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 115 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x16)) 116 | #define Sinputportp(x) ((((uptr)(x)&0x7)==0x7) &&\ 117 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1FF)==0x1DE)) 118 | #define Soutputportp(x) ((((uptr)(x)&0x7)==0x7) &&\ 119 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x2FF)==0x2DE)) 120 | #define Srecordp(x) ((((uptr)(x)&0x7)==0x7) &&\ 121 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x7)) 122 | 123 | /* Accessors */ 124 | #define Sfixnum_value(x) ((iptr)(x)/8) 125 | #define Schar_value(x) ((string_char)((uptr)(x)>>8)) 126 | #define Sboolean_value(x) ((x) != Sfalse) 127 | #define Scar(x) (*((ptr *)TO_VOIDP((uptr)(x)+7))) 128 | #define Scdr(x) (*((ptr *)TO_VOIDP((uptr)(x)+15))) 129 | #define Sflonum_value(x) (*((double *)TO_VOIDP((uptr)(x)+6))) 130 | #define Svector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 131 | #define Svector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 132 | #define Sfxvector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 133 | #define Sfxvector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 134 | #define Sflvector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 135 | #define Sflvector_ref(x,i) (((double *)TO_VOIDP((uptr)(x)+9))[i]) 136 | #define Sbytevector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>3)) 137 | #define Sbytevector_u8_ref(x,i) (((octet *)TO_VOIDP((uptr)(x)+9))[i]) 138 | /* Warning: Sbytevector_data(x) returns a pointer into x. */ 139 | #define Sbytevector_data(x) &Sbytevector_u8_ref(x,0) 140 | #define Sstring_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 141 | #define Sstring_ref(x,i) Schar_value(((string_char *)TO_VOIDP((uptr)(x)+9))[i]) 142 | #define Sunbox(x) (*((ptr *)TO_VOIDP((uptr)(x)+9))) 143 | #define Sstencil_vector_length(x) Spopcount(((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1))))>>6) 144 | #define Sstencil_vector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 145 | EXPORT iptr Sinteger_value(ptr); 146 | #define Sunsigned_value(x) (uptr)Sinteger_value(x) 147 | EXPORT Sint32_t Sinteger32_value(ptr); 148 | #define Sunsigned32_value(x) (Suint32_t)Sinteger32_value(x) 149 | EXPORT Sint64_t Sinteger64_value(ptr); 150 | EXPORT int Stry_integer_value(ptr, iptr*, const char**); 151 | EXPORT int Stry_integer32_value(ptr, Sint32_t*, const char**); 152 | EXPORT int Stry_integer64_value(ptr, Sint64_t*, const char**); 153 | #define Sunsigned64_value(x) (Suint64_t)Sinteger64_value(x) 154 | EXPORT int Stry_unsigned_value(ptr, uptr*, const char**); 155 | EXPORT int Stry_unsigned32_value(ptr, Suint32_t*, const char**); 156 | EXPORT int Stry_unsigned64_value(ptr, Suint64_t*, const char**); 157 | 158 | /* Mutators */ 159 | EXPORT void Sset_box(ptr, ptr); 160 | EXPORT void Sset_car(ptr, ptr); 161 | EXPORT void Sset_cdr(ptr, ptr); 162 | #define Sstring_set(x,i,c) ((void)((((string_char *)TO_VOIDP((uptr)(x)+9))[i]) = (string_char)(uptr)Schar(c))) 163 | #define Sfxvector_set(x,i,n) ((void)(Sfxvector_ref(x,i) = (n))) 164 | #define Sflvector_set(x,i,n) ((void)(Sflvector_ref(x,i) = (n))) 165 | #define Sbytevector_u8_set(x,i,n) ((void)(Sbytevector_u8_ref(x,i) = (n))) 166 | EXPORT void Svector_set(ptr, iptr, ptr); 167 | 168 | /* Constructors */ 169 | #define Sfixnum(x) ((ptr)(uptr)((x)*8)) 170 | #define Schar(x) ((ptr)(uptr)((x)<<8|0x16)) 171 | #define Snil ((ptr)0x26) 172 | #define Strue ((ptr)0xE) 173 | #define Sfalse ((ptr)0x6) 174 | #define Sboolean(x) ((x)?Strue:Sfalse) 175 | #define Sbwp_object ((ptr)0x4E) 176 | #define Seof_object ((ptr)0x36) 177 | #define Svoid ((ptr)0x2E) 178 | EXPORT ptr Scons(ptr, ptr); 179 | EXPORT ptr Sstring_to_symbol(const char *); 180 | EXPORT ptr Ssymbol_to_string(ptr); 181 | EXPORT ptr Sflonum(double); 182 | EXPORT ptr Smake_vector(iptr, ptr); 183 | EXPORT ptr Smake_fxvector(iptr, ptr); 184 | EXPORT ptr Smake_flvector(iptr, double); 185 | EXPORT ptr Smake_bytevector(iptr, int); 186 | EXPORT ptr Smake_string(iptr, int); 187 | EXPORT ptr Smake_uninitialized_string(iptr); 188 | EXPORT ptr Sstring(const char *); 189 | EXPORT ptr Sstring_of_length(const char *, iptr); 190 | EXPORT ptr Sstring_utf8(const char*, iptr); 191 | EXPORT ptr Sbox(ptr); 192 | EXPORT ptr Sinteger(iptr); 193 | EXPORT ptr Sunsigned(uptr); 194 | EXPORT ptr Sinteger32(Sint32_t); 195 | EXPORT ptr Sunsigned32(Suint32_t); 196 | EXPORT ptr Sinteger64(Sint64_t); 197 | EXPORT ptr Sunsigned64(Suint64_t); 198 | 199 | /* Records */ 200 | #define Srecord_uniform_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 201 | EXPORT ptr Srecord_type(ptr); 202 | EXPORT ptr Srecord_type_parent(ptr); 203 | EXPORT int Srecord_type_uniformp(ptr); 204 | EXPORT uptr Srecord_type_size(ptr); 205 | 206 | /* Miscellaneous */ 207 | EXPORT ptr Stop_level_value(ptr); 208 | EXPORT void Sset_top_level_value(ptr, ptr); 209 | EXPORT void Slock_object(ptr); 210 | EXPORT void Sunlock_object(ptr); 211 | EXPORT int Slocked_objectp(ptr); 212 | EXPORT void Sforeign_symbol(const char *, void *); 213 | EXPORT void Sregister_symbol(const char *, void *); 214 | 215 | /* Support for calls into Scheme */ 216 | EXPORT ptr Scall0(ptr); 217 | EXPORT ptr Scall1(ptr, ptr); 218 | EXPORT ptr Scall2(ptr, ptr, ptr); 219 | EXPORT ptr Scall3(ptr, ptr, ptr, ptr); 220 | EXPORT void Sinitframe(iptr); 221 | EXPORT void Sput_arg(iptr, ptr); 222 | EXPORT ptr Scall(ptr, iptr); 223 | #define Sforeign_callable_entry_point(x) TO_PTR(Svector_ref(x, 2)) 224 | EXPORT ptr Sforeign_callable_code_object(void*); 225 | 226 | /* Customization support. */ 227 | EXPORT const char * Skernel_version(void); 228 | EXPORT void Sretain_static_relocation(void); 229 | EXPORT void Sset_verbose(int); 230 | EXPORT void Sscheme_init(void (*)(void)); 231 | EXPORT void Sregister_boot_file(const char *); 232 | EXPORT void Sregister_boot_executable_relative_file(const char *, const char *); 233 | EXPORT void Sregister_boot_relative_file(const char *); 234 | EXPORT void Sregister_boot_file_fd(const char *, int); 235 | EXPORT void Sregister_boot_file_fd_region(const char *, int, iptr, iptr, int); 236 | EXPORT void Sregister_boot_file_bytes(const char *, void *, iptr); 237 | EXPORT void Sregister_heap_file(const char *); 238 | EXPORT void Scompact_heap(void); 239 | EXPORT void Ssave_heap(const char *, int); 240 | EXPORT void Sbuild_heap(const char *, void (*)(void)); 241 | EXPORT void Senable_expeditor(const char *); 242 | EXPORT int Sscheme_start(int, const char *[]); 243 | EXPORT int Sscheme_script(const char *, int, const char *[]); 244 | EXPORT int Sscheme_program(const char *, int, const char *[]); 245 | EXPORT void Sscheme_deinit(void); 246 | EXPORT void Sscheme_register_signal_registerer(void (*f)(int)); 247 | EXPORT void Sregister_pbchunks(void **, int, int); 248 | 249 | /* Thread support. */ 250 | EXPORT int Sactivate_thread(void); 251 | EXPORT void Sdeactivate_thread(void); 252 | EXPORT int Sdestroy_thread(void); 253 | 254 | /* Windows support. */ 255 | #if defined(FEATURE_WINDOWS) 256 | #include 257 | EXPORT char * Sgetenv(const char *); 258 | EXPORT wchar_t * Sutf8_to_wide(const char *); 259 | EXPORT char * Swide_to_utf8(const wchar_t *); 260 | #endif 261 | 262 | /* Features. */ 263 | #define FEATURE_ICONV 264 | #define FEATURE_EXPEDITOR 265 | #define FEATURE_PTHREADS 266 | #define FEATURE_PBCHUNK 267 | 268 | /* C call prototypes. */ 269 | #include 270 | typedef void (*pb_void_t)(); 271 | typedef void (*pb_void_uptr_t)(uptr); 272 | typedef void (*pb_void_int32_t)(int32_t); 273 | typedef void (*pb_void_uint32_t)(uint32_t); 274 | typedef void (*pb_void_voids_t)(void*); 275 | typedef void (*pb_void_uptr_uint32_t)(uptr, uint32_t); 276 | typedef void (*pb_void_int32_uptr_t)(int32_t, uptr); 277 | typedef void (*pb_void_int32_int32_t)(int32_t, int32_t); 278 | typedef void (*pb_void_uint32_uint32_t)(uint32_t, uint32_t); 279 | typedef void (*pb_void_uptr_uptr_t)(uptr, uptr); 280 | typedef void (*pb_void_int32_voids_t)(int32_t, void*); 281 | typedef void (*pb_void_uptr_voids_t)(uptr, void*); 282 | typedef void (*pb_void_voids_voids_t)(void*, void*); 283 | typedef void (*pb_void_uptr_uptr_uptr_t)(uptr, uptr, uptr); 284 | typedef void (*pb_void_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr, uptr); 285 | typedef int32_t (*pb_int32_t)(); 286 | typedef int32_t (*pb_int32_int32_t)(int32_t); 287 | typedef int32_t (*pb_int32_uptr_t)(uptr); 288 | typedef int32_t (*pb_int32_voids_t)(void*); 289 | typedef int32_t (*pb_int32_int32_uptr_t)(int32_t, uptr); 290 | typedef int32_t (*pb_int32_uptr_int32_t)(uptr, int32_t); 291 | typedef int32_t (*pb_int32_uptr_uptr_t)(uptr, uptr); 292 | typedef int32_t (*pb_int32_int32_int32_t)(int32_t, int32_t); 293 | typedef int32_t (*pb_int32_int32_voids_t)(int32_t, void*); 294 | typedef int32_t (*pb_int32_voids_int32_t)(void*, int32_t); 295 | typedef int32_t (*pb_int32_double_double_double_double_double_double_t)(double, double, double, double, double, double); 296 | typedef int32_t (*pb_int32_voids_voids_voids_voids_uptr_t)(void*, void*, void*, void*, uptr); 297 | typedef uint32_t (*pb_uint32_t)(); 298 | typedef double (*pb_double_double_t)(double); 299 | typedef double (*pb_double_uptr_t)(uptr); 300 | typedef double (*pb_double_double_double_t)(double, double); 301 | typedef int32_t (*pb_int32_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr, uptr); 302 | typedef int32_t (*pb_int32_uptr_uptr_uptr_t)(uptr, uptr, uptr); 303 | typedef uptr (*pb_uptr_t)(); 304 | typedef uptr (*pb_uptr_uptr_t)(uptr); 305 | typedef uptr (*pb_uptr_int32_t)(int32_t); 306 | typedef uptr (*pb_uptr_voids_t)(void*); 307 | typedef uptr (*pb_uptr_uptr_uptr_t)(uptr, uptr); 308 | typedef uptr (*pb_uptr_uptr_int32_t)(uptr, int32_t); 309 | typedef uptr (*pb_uptr_int32_uptr_t)(int32_t, uptr); 310 | typedef uptr (*pb_uptr_uptr_int64_t)(uptr, int64_t); 311 | typedef uptr (*pb_uptr_uptr_voids_t)(uptr, void*); 312 | typedef uptr (*pb_uptr_voids_uptr_t)(void*, uptr); 313 | typedef uptr (*pb_uptr_voids_int32_t)(void*, int32_t); 314 | typedef uptr (*pb_uptr_voids_voids_t)(void*, void*); 315 | typedef uptr (*pb_uptr_uptr_int32_int32_t)(uptr, int32_t, int32_t); 316 | typedef uptr (*pb_uptr_uptr_uptr_int32_t)(uptr, uptr, int32_t); 317 | typedef uptr (*pb_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr); 318 | typedef uptr (*pb_uptr_int32_int32_uptr_t)(int32_t, int32_t, uptr); 319 | typedef uptr (*pb_uptr_voids_int32_int32_t)(void*, int32_t, int32_t); 320 | typedef uptr (*pb_uptr_voids_uptr_uptr_t)(void*, uptr, uptr); 321 | typedef uptr (*pb_uptr_int32_uptr_uptr_uptr_t)(int32_t, uptr, uptr, uptr); 322 | typedef uptr (*pb_uptr_int32_int32_uptr_uptr_t)(int32_t, int32_t, uptr, uptr); 323 | typedef uptr (*pb_uptr_int32_voids_uptr_uptr_t)(int32_t, void*, uptr, uptr); 324 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr); 325 | typedef uptr (*pb_uptr_int32_int32_int32_uptr_t)(int32_t, int32_t, int32_t, uptr); 326 | typedef uptr (*pb_uptr_uptr_voids_uptr_uptr_t)(uptr, void*, uptr, uptr); 327 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_int32_t)(uptr, uptr, uptr, uptr, int32_t); 328 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr, uptr); 329 | typedef uptr (*pb_uptr_voids_voids_voids_voids_uptr_t)(void*, void*, void*, void*, uptr); 330 | typedef uptr (*pb_uptr_uptr_int32_uptr_uptr_uptr_uptr_t)(uptr, int32_t, uptr, uptr, uptr, uptr); 331 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr, uptr, uptr); 332 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_uptr_uptr_int32_t)(uptr, uptr, uptr, uptr, uptr, uptr, int32_t); 333 | typedef uptr (*pb_uptr_uptr_uptr_uptr_uptr_uptr_uptr_uptr_t)(uptr, uptr, uptr, uptr, uptr, uptr, uptr); 334 | typedef uptr (*pb_uptr_double_double_double_double_double_double_t)(double, double, double, double, double, double); 335 | typedef void* (*pb_voids_t)(); 336 | typedef void* (*pb_voids_uptr_t)(uptr); 337 | 338 | /* Locking macros. */ 339 | #define INITLOCK(addr) (*((long *) addr) = 0) 340 | #define UNLOCK(addr) (*((long *) addr) = 0) 341 | #define SPINLOCK(addr) S_pb_spinlock(addr) 342 | #define LOCKED_INCR(addr, res) (res = S_pb_locked_adjust(addr, 1)) 343 | #define LOCKED_DECR(addr, res) (res = S_pb_locked_adjust(addr, -1)) 344 | EXPORT void S_pb_spinlock(void*); 345 | EXPORT int S_pb_locked_adjust(void*, int); 346 | -------------------------------------------------------------------------------- /Lib/include/chezscheme-arm64-macos.h: -------------------------------------------------------------------------------- 1 | /* scheme.h for Chez Scheme Version 10.2.0-pre-release.2 (tarm64osx) */ 2 | 3 | /* Do not edit this file. It is automatically generated and */ 4 | /* specifically tailored to the version of Chez Scheme named */ 5 | /* above. Always be certain that you have the correct scheme.h */ 6 | /* for the version of Chez Scheme you are using. */ 7 | 8 | /* Warning: Some macros may evaluate arguments more than once. */ 9 | 10 | /* Specify declaration of exports. */ 11 | #ifdef _WIN32 12 | # if __cplusplus 13 | # ifdef SCHEME_IMPORT 14 | # define EXPORT extern "C" __declspec (dllimport) 15 | # elif SCHEME_STATIC 16 | # define EXPORT extern "C" 17 | # else 18 | # define EXPORT extern "C" __declspec (dllexport) 19 | # endif 20 | # else 21 | # ifdef SCHEME_IMPORT 22 | # define EXPORT extern __declspec (dllimport) 23 | # elif SCHEME_STATIC 24 | # define EXPORT extern 25 | # else 26 | # define EXPORT extern __declspec (dllexport) 27 | # endif 28 | # endif 29 | #else 30 | # if __cplusplus 31 | # define EXPORT extern "C" 32 | # else 33 | # define EXPORT extern 34 | # endif 35 | #endif 36 | 37 | /* Chez Scheme Version and machine type */ 38 | #define VERSION "10.2.0-pre-release.2" 39 | #define MACHINE_TYPE "tarm64osx" 40 | 41 | /* Integer typedefs */ 42 | typedef int Sint32_t; 43 | typedef unsigned int Suint32_t; 44 | typedef long Sint64_t; 45 | typedef unsigned long Suint64_t; 46 | 47 | /* All Scheme objects are of type ptr. Type iptr and */ 48 | /* uptr are signed and unsigned ints of the same size */ 49 | /* as a ptr */ 50 | typedef void * ptr; 51 | typedef long iptr; 52 | typedef unsigned long uptr; 53 | typedef ptr xptr; 54 | 55 | /* The `uptr` and `ptr` types are the same width, but `ptr` */ 56 | /* can be either an integer type or a pointer type; it may */ 57 | /* be larger than a pointer type. */ 58 | /* Use `TO_VOIDP` to get from the `uptr`/`ptr` world to the */ 59 | /* C pointer worlds, and use `TO_PTR` to go the other way. */ 60 | #ifdef PORTABLE_BYTECODE 61 | # define TO_VOIDP(p) ((void *)(intptr_t)(p)) 62 | # define TO_PTR(p) ((ptr)(intptr_t)(p)) 63 | #else 64 | # define TO_VOIDP(p) ((void *)(p)) 65 | # define TO_PTR(p) ((ptr)(p)) 66 | #endif 67 | 68 | /* String elements are 32-bit tagged char objects */ 69 | typedef unsigned int string_char; 70 | 71 | /* Bytevector elements are 8-bit unsigned "octets" */ 72 | typedef unsigned char octet; 73 | 74 | /* Type predicates */ 75 | #define Sfixnump(x) (((uptr)(x)&0x7)==0x0) 76 | #define Scharp(x) (((uptr)(x)&0xFF)==0x16) 77 | #define Snullp(x) ((uptr)(x)==0x26) 78 | #define Seof_objectp(x) ((uptr)(x)==0x36) 79 | #define Sbwp_objectp(x) ((uptr)(x)==0x4E) 80 | #define Sbooleanp(x) (((uptr)(x)&0xF7)==0x6) 81 | #define Spairp(x) (((uptr)(x)&0x7)==0x1) 82 | #define Ssymbolp(x) (((uptr)(x)&0x7)==0x3) 83 | #define Sprocedurep(x) (((uptr)(x)&0x7)==0x5) 84 | #define Sflonump(x) (((uptr)(x)&0x7)==0x2) 85 | #define Svectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 86 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x0)) 87 | #define Sfxvectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 88 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xF)==0x3)) 89 | #define Sflvectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 90 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xF)==0xB)) 91 | #define Sbytevectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 92 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3)==0x1)) 93 | #define Sstringp(x) ((((uptr)(x)&0x7)==0x7) &&\ 94 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x2)) 95 | #define Sstencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 96 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3F)==0xE)) 97 | #define Ssystem_stencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 98 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3F)==0x2E)) 99 | #define Sany_stencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 100 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1F)==0xE)) 101 | #define Sbignump(x) ((((uptr)(x)&0x7)==0x7) &&\ 102 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1F)==0x6)) 103 | #define Sboxp(x) ((((uptr)(x)&0x7)==0x7) &&\ 104 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xFF)==0x1E)) 105 | #define Sinexactnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 106 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x36)) 107 | #define Sexactnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 108 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x56)) 109 | #define Sratnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 110 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x16)) 111 | #define Sinputportp(x) ((((uptr)(x)&0x7)==0x7) &&\ 112 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1FF)==0x1DE)) 113 | #define Soutputportp(x) ((((uptr)(x)&0x7)==0x7) &&\ 114 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x2FF)==0x2DE)) 115 | #define Srecordp(x) ((((uptr)(x)&0x7)==0x7) &&\ 116 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x7)) 117 | 118 | /* Accessors */ 119 | #define Sfixnum_value(x) ((iptr)(x)/8) 120 | #define Schar_value(x) ((string_char)((uptr)(x)>>8)) 121 | #define Sboolean_value(x) ((x) != Sfalse) 122 | #define Scar(x) (*((ptr *)TO_VOIDP((uptr)(x)+7))) 123 | #define Scdr(x) (*((ptr *)TO_VOIDP((uptr)(x)+15))) 124 | #define Sflonum_value(x) (*((double *)TO_VOIDP((uptr)(x)+6))) 125 | #define Svector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 126 | #define Svector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 127 | #define Sfxvector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 128 | #define Sfxvector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 129 | #define Sflvector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 130 | #define Sflvector_ref(x,i) (((double *)TO_VOIDP((uptr)(x)+9))[i]) 131 | #define Sbytevector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>3)) 132 | #define Sbytevector_u8_ref(x,i) (((octet *)TO_VOIDP((uptr)(x)+9))[i]) 133 | /* Warning: Sbytevector_data(x) returns a pointer into x. */ 134 | #define Sbytevector_data(x) &Sbytevector_u8_ref(x,0) 135 | #define Sstring_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 136 | #define Sstring_ref(x,i) Schar_value(((string_char *)TO_VOIDP((uptr)(x)+9))[i]) 137 | #define Sunbox(x) (*((ptr *)TO_VOIDP((uptr)(x)+9))) 138 | #define Sstencil_vector_length(x) Spopcount(((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1))))>>6) 139 | #define Sstencil_vector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 140 | EXPORT iptr Sinteger_value(ptr); 141 | #define Sunsigned_value(x) (uptr)Sinteger_value(x) 142 | EXPORT Sint32_t Sinteger32_value(ptr); 143 | #define Sunsigned32_value(x) (Suint32_t)Sinteger32_value(x) 144 | EXPORT Sint64_t Sinteger64_value(ptr); 145 | EXPORT int Stry_integer_value(ptr, iptr*, const char**); 146 | EXPORT int Stry_integer32_value(ptr, Sint32_t*, const char**); 147 | EXPORT int Stry_integer64_value(ptr, Sint64_t*, const char**); 148 | #define Sunsigned64_value(x) (Suint64_t)Sinteger64_value(x) 149 | EXPORT int Stry_unsigned_value(ptr, uptr*, const char**); 150 | EXPORT int Stry_unsigned32_value(ptr, Suint32_t*, const char**); 151 | EXPORT int Stry_unsigned64_value(ptr, Suint64_t*, const char**); 152 | 153 | /* Mutators */ 154 | EXPORT void Sset_box(ptr, ptr); 155 | EXPORT void Sset_car(ptr, ptr); 156 | EXPORT void Sset_cdr(ptr, ptr); 157 | #define Sstring_set(x,i,c) ((void)((((string_char *)TO_VOIDP((uptr)(x)+9))[i]) = (string_char)(uptr)Schar(c))) 158 | #define Sfxvector_set(x,i,n) ((void)(Sfxvector_ref(x,i) = (n))) 159 | #define Sflvector_set(x,i,n) ((void)(Sflvector_ref(x,i) = (n))) 160 | #define Sbytevector_u8_set(x,i,n) ((void)(Sbytevector_u8_ref(x,i) = (n))) 161 | EXPORT void Svector_set(ptr, iptr, ptr); 162 | 163 | /* Constructors */ 164 | #define Sfixnum(x) ((ptr)(uptr)((x)*8)) 165 | #define Schar(x) ((ptr)(uptr)((x)<<8|0x16)) 166 | #define Snil ((ptr)0x26) 167 | #define Strue ((ptr)0xE) 168 | #define Sfalse ((ptr)0x6) 169 | #define Sboolean(x) ((x)?Strue:Sfalse) 170 | #define Sbwp_object ((ptr)0x4E) 171 | #define Seof_object ((ptr)0x36) 172 | #define Svoid ((ptr)0x2E) 173 | EXPORT ptr Scons(ptr, ptr); 174 | EXPORT ptr Sstring_to_symbol(const char *); 175 | EXPORT ptr Ssymbol_to_string(ptr); 176 | EXPORT ptr Sflonum(double); 177 | EXPORT ptr Smake_vector(iptr, ptr); 178 | EXPORT ptr Smake_fxvector(iptr, ptr); 179 | EXPORT ptr Smake_flvector(iptr, double); 180 | EXPORT ptr Smake_bytevector(iptr, int); 181 | EXPORT ptr Smake_string(iptr, int); 182 | EXPORT ptr Smake_uninitialized_string(iptr); 183 | EXPORT ptr Sstring(const char *); 184 | EXPORT ptr Sstring_of_length(const char *, iptr); 185 | EXPORT ptr Sstring_utf8(const char*, iptr); 186 | EXPORT ptr Sbox(ptr); 187 | EXPORT ptr Sinteger(iptr); 188 | EXPORT ptr Sunsigned(uptr); 189 | EXPORT ptr Sinteger32(Sint32_t); 190 | EXPORT ptr Sunsigned32(Suint32_t); 191 | EXPORT ptr Sinteger64(Sint64_t); 192 | EXPORT ptr Sunsigned64(Suint64_t); 193 | 194 | /* Records */ 195 | #define Srecord_uniform_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 196 | EXPORT ptr Srecord_type(ptr); 197 | EXPORT ptr Srecord_type_parent(ptr); 198 | EXPORT int Srecord_type_uniformp(ptr); 199 | EXPORT uptr Srecord_type_size(ptr); 200 | 201 | /* Miscellaneous */ 202 | EXPORT ptr Stop_level_value(ptr); 203 | EXPORT void Sset_top_level_value(ptr, ptr); 204 | EXPORT void Slock_object(ptr); 205 | EXPORT void Sunlock_object(ptr); 206 | EXPORT int Slocked_objectp(ptr); 207 | EXPORT void Sforeign_symbol(const char *, void *); 208 | EXPORT void Sregister_symbol(const char *, void *); 209 | 210 | /* Support for calls into Scheme */ 211 | EXPORT ptr Scall0(ptr); 212 | EXPORT ptr Scall1(ptr, ptr); 213 | EXPORT ptr Scall2(ptr, ptr, ptr); 214 | EXPORT ptr Scall3(ptr, ptr, ptr, ptr); 215 | EXPORT void Sinitframe(iptr); 216 | EXPORT void Sput_arg(iptr, ptr); 217 | EXPORT ptr Scall(ptr, iptr); 218 | /* Warning: Sforeign_callable_entry_point(x) returns a pointer into x. */ 219 | #define Sforeign_callable_entry_point(x) ((void (*)(void))TO_VOIDP((uptr)(x)+65)) 220 | #define Sforeign_callable_code_object(x) ((ptr)TO_VOIDP((uptr)(x)-65)) 221 | 222 | /* Customization support. */ 223 | EXPORT const char * Skernel_version(void); 224 | EXPORT void Sretain_static_relocation(void); 225 | EXPORT void Sset_verbose(int); 226 | EXPORT void Sscheme_init(void (*)(void)); 227 | EXPORT void Sregister_boot_file(const char *); 228 | EXPORT void Sregister_boot_executable_relative_file(const char *, const char *); 229 | EXPORT void Sregister_boot_relative_file(const char *); 230 | EXPORT void Sregister_boot_file_fd(const char *, int); 231 | EXPORT void Sregister_boot_file_fd_region(const char *, int, iptr, iptr, int); 232 | EXPORT void Sregister_boot_file_bytes(const char *, void *, iptr); 233 | EXPORT void Sregister_heap_file(const char *); 234 | EXPORT void Scompact_heap(void); 235 | EXPORT void Ssave_heap(const char *, int); 236 | EXPORT void Sbuild_heap(const char *, void (*)(void)); 237 | EXPORT void Senable_expeditor(const char *); 238 | EXPORT int Sscheme_start(int, const char *[]); 239 | EXPORT int Sscheme_script(const char *, int, const char *[]); 240 | EXPORT int Sscheme_program(const char *, int, const char *[]); 241 | EXPORT void Sscheme_deinit(void); 242 | EXPORT void Sscheme_register_signal_registerer(void (*f)(int)); 243 | 244 | /* Thread support. */ 245 | EXPORT int Sactivate_thread(void); 246 | EXPORT void Sdeactivate_thread(void); 247 | EXPORT int Sdestroy_thread(void); 248 | 249 | /* Features. */ 250 | #define FEATURE_ICONV 251 | #define FEATURE_EXPEDITOR 252 | #define FEATURE_PTHREADS 253 | 254 | /* Locking macros. */ 255 | #define INITLOCK(addr) \ 256 | __asm__ __volatile__ ("mov x12, #0\n\t"\ 257 | "str x12, [%0, #0]\n\t"\ 258 | : \ 259 | : "r" (addr)\ 260 | :"memory", "x12") 261 | 262 | #define SPINLOCK(addr) \ 263 | __asm__ __volatile__ ("0:\n\t"\ 264 | "ldxr x12, [%0, #0]\n\t"\ 265 | "cmp x12, #0\n\t"\ 266 | "bne 1f\n\t"\ 267 | "mov x12, #1\n\t"\ 268 | "stxr w7, x12, [%0]\n\t"\ 269 | "cmp w7, #0\n\t"\ 270 | "beq 2f\n\t"\ 271 | "1:\n\t"\ 272 | "ldr x12, [%0, #0]\n\t"\ 273 | "cmp x12, #0\n\t"\ 274 | "beq 0b\n\t"\ 275 | "b 1b\n\t"\ 276 | "2:\n\t"\ 277 | : \ 278 | : "r" (addr)\ 279 | : "cc", "memory", "x12", "x7") 280 | 281 | #define UNLOCK(addr) \ 282 | __asm__ __volatile__ ("mov x12, #0\n\t"\ 283 | "str x12, [%0, #0]\n\t"\ 284 | : \ 285 | : "r" (addr)\ 286 | :"memory", "x12") 287 | 288 | #define LOCKED_INCR(addr, ret) \ 289 | do {\ 290 | long _return_;\ 291 | __asm__ __volatile__ ("mov %0, #0\n\t"\ 292 | "0:\n\t"\ 293 | "ldxr x12, [%1, #0]\n\t"\ 294 | "add x12, x12, #1\n\t"\ 295 | "stxr w7, x12, [%1]\n\t"\ 296 | "cmp w7, #0\n\t"\ 297 | "bne 0b\n\t"\ 298 | "cmp x12, #0\n\t"\ 299 | "bne 1f\n\t"\ 300 | "mov %0, #1\n\t"\ 301 | "1:\n\t"\ 302 | : "=&r" (_return_)\ 303 | : "r" (addr)\ 304 | : "cc", "memory", "x12", "x7");\ 305 | ret = _return_;\ 306 | } while (0) 307 | 308 | #define LOCKED_DECR(addr, ret) \ 309 | do {\ 310 | long _return_;\ 311 | __asm__ __volatile__ ("mov %0, #0\n\t"\ 312 | "0:\n\t"\ 313 | "ldxr x12, [%1, #0]\n\t"\ 314 | "sub x12, x12, #1\n\t"\ 315 | "stxr w7, x12, [%1]\n\t"\ 316 | "cmp w7, #0\n\t"\ 317 | "bne 0b\n\t"\ 318 | "cmp x12, #0\n\t"\ 319 | "bne 1f\n\t"\ 320 | "mov %0, #1\n\t"\ 321 | "1:\n\t"\ 322 | : "=&r" (_return_)\ 323 | : "r" (addr)\ 324 | : "cc", "memory", "x12", "x7");\ 325 | ret = _return_;\ 326 | } while (0) 327 | -------------------------------------------------------------------------------- /Lib/include/chezscheme-x86_64-macos.h: -------------------------------------------------------------------------------- 1 | /* scheme.h for Chez Scheme Version 10.1.0-pre-release.4 (ta6osx) */ 2 | 3 | /* Do not edit this file. It is automatically generated and */ 4 | /* specifically tailored to the version of Chez Scheme named */ 5 | /* above. Always be certain that you have the correct scheme.h */ 6 | /* for the version of Chez Scheme you are using. */ 7 | 8 | /* Warning: Some macros may evaluate arguments more than once. */ 9 | 10 | /* Specify declaration of exports. */ 11 | #ifdef _WIN32 12 | # if __cplusplus 13 | # ifdef SCHEME_IMPORT 14 | # define EXPORT extern "C" __declspec (dllimport) 15 | # elif SCHEME_STATIC 16 | # define EXPORT extern "C" 17 | # else 18 | # define EXPORT extern "C" __declspec (dllexport) 19 | # endif 20 | # else 21 | # ifdef SCHEME_IMPORT 22 | # define EXPORT extern __declspec (dllimport) 23 | # elif SCHEME_STATIC 24 | # define EXPORT extern 25 | # else 26 | # define EXPORT extern __declspec (dllexport) 27 | # endif 28 | # endif 29 | #else 30 | # if __cplusplus 31 | # define EXPORT extern "C" 32 | # else 33 | # define EXPORT extern 34 | # endif 35 | #endif 36 | 37 | /* Chez Scheme Version and machine type */ 38 | #define VERSION "10.1.0-pre-release.4" 39 | #define MACHINE_TYPE "ta6osx" 40 | 41 | /* Integer typedefs */ 42 | typedef int Sint32_t; 43 | typedef unsigned int Suint32_t; 44 | typedef long Sint64_t; 45 | typedef unsigned long Suint64_t; 46 | 47 | /* All Scheme objects are of type ptr. Type iptr and */ 48 | /* uptr are signed and unsigned ints of the same size */ 49 | /* as a ptr */ 50 | typedef void * ptr; 51 | typedef long iptr; 52 | typedef unsigned long uptr; 53 | typedef ptr xptr; 54 | 55 | /* The `uptr` and `ptr` types are the same width, but `ptr` */ 56 | /* can be either an integer type or a pointer type; it may */ 57 | /* be larger than a pointer type. */ 58 | /* Use `TO_VOIDP` to get from the `uptr`/`ptr` world to the */ 59 | /* C pointer worlds, and use `TO_PTR` to go the other way. */ 60 | #ifdef PORTABLE_BYTECODE 61 | # define TO_VOIDP(p) ((void *)(intptr_t)(p)) 62 | # define TO_PTR(p) ((ptr)(intptr_t)(p)) 63 | #else 64 | # define TO_VOIDP(p) ((void *)(p)) 65 | # define TO_PTR(p) ((ptr)(p)) 66 | #endif 67 | 68 | /* String elements are 32-bit tagged char objects */ 69 | typedef unsigned int string_char; 70 | 71 | /* Bytevector elements are 8-bit unsigned "octets" */ 72 | typedef unsigned char octet; 73 | 74 | /* Type predicates */ 75 | #define Sfixnump(x) (((uptr)(x)&0x7)==0x0) 76 | #define Scharp(x) (((uptr)(x)&0xFF)==0x16) 77 | #define Snullp(x) ((uptr)(x)==0x26) 78 | #define Seof_objectp(x) ((uptr)(x)==0x36) 79 | #define Sbwp_objectp(x) ((uptr)(x)==0x4E) 80 | #define Sbooleanp(x) (((uptr)(x)&0xF7)==0x6) 81 | #define Spairp(x) (((uptr)(x)&0x7)==0x1) 82 | #define Ssymbolp(x) (((uptr)(x)&0x7)==0x3) 83 | #define Sprocedurep(x) (((uptr)(x)&0x7)==0x5) 84 | #define Sflonump(x) (((uptr)(x)&0x7)==0x2) 85 | #define Svectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 86 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x0)) 87 | #define Sfxvectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 88 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xF)==0x3)) 89 | #define Sflvectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 90 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xF)==0xB)) 91 | #define Sbytevectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 92 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3)==0x1)) 93 | #define Sstringp(x) ((((uptr)(x)&0x7)==0x7) &&\ 94 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x2)) 95 | #define Sstencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 96 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3F)==0xE)) 97 | #define Ssystem_stencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 98 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x3F)==0x2E)) 99 | #define Sany_stencil_vectorp(x) ((((uptr)(x)&0x7)==0x7) &&\ 100 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1F)==0xE)) 101 | #define Sbignump(x) ((((uptr)(x)&0x7)==0x7) &&\ 102 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1F)==0x6)) 103 | #define Sboxp(x) ((((uptr)(x)&0x7)==0x7) &&\ 104 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0xFF)==0x1E)) 105 | #define Sinexactnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 106 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x36)) 107 | #define Sexactnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 108 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x56)) 109 | #define Sratnump(x) ((((uptr)(x)&0x7)==0x7) &&\ 110 | ((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))==0x16)) 111 | #define Sinputportp(x) ((((uptr)(x)&0x7)==0x7) &&\ 112 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x1FF)==0x1DE)) 113 | #define Soutputportp(x) ((((uptr)(x)&0x7)==0x7) &&\ 114 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x2FF)==0x2DE)) 115 | #define Srecordp(x) ((((uptr)(x)&0x7)==0x7) &&\ 116 | (((uptr)((*((ptr *)TO_VOIDP((uptr)(x)+1))))&0x7)==0x7)) 117 | 118 | /* Accessors */ 119 | #define Sfixnum_value(x) ((iptr)(x)/8) 120 | #define Schar_value(x) ((string_char)((uptr)(x)>>8)) 121 | #define Sboolean_value(x) ((x) != Sfalse) 122 | #define Scar(x) (*((ptr *)TO_VOIDP((uptr)(x)+7))) 123 | #define Scdr(x) (*((ptr *)TO_VOIDP((uptr)(x)+15))) 124 | #define Sflonum_value(x) (*((double *)TO_VOIDP((uptr)(x)+6))) 125 | #define Svector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 126 | #define Svector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 127 | #define Sfxvector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 128 | #define Sfxvector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 129 | #define Sflvector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 130 | #define Sflvector_ref(x,i) (((double *)TO_VOIDP((uptr)(x)+9))[i]) 131 | #define Sbytevector_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>3)) 132 | #define Sbytevector_u8_ref(x,i) (((octet *)TO_VOIDP((uptr)(x)+9))[i]) 133 | /* Warning: Sbytevector_data(x) returns a pointer into x. */ 134 | #define Sbytevector_data(x) &Sbytevector_u8_ref(x,0) 135 | #define Sstring_length(x) ((iptr)((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1)))>>4)) 136 | #define Sstring_ref(x,i) Schar_value(((string_char *)TO_VOIDP((uptr)(x)+9))[i]) 137 | #define Sunbox(x) (*((ptr *)TO_VOIDP((uptr)(x)+9))) 138 | #define Sstencil_vector_length(x) Spopcount(((uptr)(*((iptr *)TO_VOIDP((uptr)(x)+1))))>>6) 139 | #define Sstencil_vector_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 140 | EXPORT iptr Sinteger_value(ptr); 141 | #define Sunsigned_value(x) (uptr)Sinteger_value(x) 142 | EXPORT Sint32_t Sinteger32_value(ptr); 143 | #define Sunsigned32_value(x) (Suint32_t)Sinteger32_value(x) 144 | EXPORT Sint64_t Sinteger64_value(ptr); 145 | EXPORT int Stry_integer_value(ptr, iptr*, const char**); 146 | EXPORT int Stry_integer32_value(ptr, Sint32_t*, const char**); 147 | EXPORT int Stry_integer64_value(ptr, Sint64_t*, const char**); 148 | #define Sunsigned64_value(x) (Suint64_t)Sinteger64_value(x) 149 | EXPORT int Stry_unsigned_value(ptr, uptr*, const char**); 150 | EXPORT int Stry_unsigned32_value(ptr, Suint32_t*, const char**); 151 | EXPORT int Stry_unsigned64_value(ptr, Suint64_t*, const char**); 152 | 153 | /* Mutators */ 154 | EXPORT void Sset_box(ptr, ptr); 155 | EXPORT void Sset_car(ptr, ptr); 156 | EXPORT void Sset_cdr(ptr, ptr); 157 | #define Sstring_set(x,i,c) ((void)((((string_char *)TO_VOIDP((uptr)(x)+9))[i]) = (string_char)(uptr)Schar(c))) 158 | #define Sfxvector_set(x,i,n) ((void)(Sfxvector_ref(x,i) = (n))) 159 | #define Sflvector_set(x,i,n) ((void)(Sflvector_ref(x,i) = (n))) 160 | #define Sbytevector_u8_set(x,i,n) ((void)(Sbytevector_u8_ref(x,i) = (n))) 161 | EXPORT void Svector_set(ptr, iptr, ptr); 162 | 163 | /* Constructors */ 164 | #define Sfixnum(x) ((ptr)(uptr)((x)*8)) 165 | #define Schar(x) ((ptr)(uptr)((x)<<8|0x16)) 166 | #define Snil ((ptr)0x26) 167 | #define Strue ((ptr)0xE) 168 | #define Sfalse ((ptr)0x6) 169 | #define Sboolean(x) ((x)?Strue:Sfalse) 170 | #define Sbwp_object ((ptr)0x4E) 171 | #define Seof_object ((ptr)0x36) 172 | #define Svoid ((ptr)0x2E) 173 | EXPORT ptr Scons(ptr, ptr); 174 | EXPORT ptr Sstring_to_symbol(const char *); 175 | EXPORT ptr Ssymbol_to_string(ptr); 176 | EXPORT ptr Sflonum(double); 177 | EXPORT ptr Smake_vector(iptr, ptr); 178 | EXPORT ptr Smake_fxvector(iptr, ptr); 179 | EXPORT ptr Smake_flvector(iptr, double); 180 | EXPORT ptr Smake_bytevector(iptr, int); 181 | EXPORT ptr Smake_string(iptr, int); 182 | EXPORT ptr Smake_uninitialized_string(iptr); 183 | EXPORT ptr Sstring(const char *); 184 | EXPORT ptr Sstring_of_length(const char *, iptr); 185 | EXPORT ptr Sstring_utf8(const char*, iptr); 186 | EXPORT ptr Sbox(ptr); 187 | EXPORT ptr Sinteger(iptr); 188 | EXPORT ptr Sunsigned(uptr); 189 | EXPORT ptr Sinteger32(Sint32_t); 190 | EXPORT ptr Sunsigned32(Suint32_t); 191 | EXPORT ptr Sinteger64(Sint64_t); 192 | EXPORT ptr Sunsigned64(Suint64_t); 193 | 194 | /* Records */ 195 | #define Srecord_uniform_ref(x,i) (((ptr *)TO_VOIDP((uptr)(x)+9))[i]) 196 | EXPORT ptr Srecord_type(ptr); 197 | EXPORT ptr Srecord_type_parent(ptr); 198 | EXPORT int Srecord_type_uniformp(ptr); 199 | EXPORT uptr Srecord_type_size(ptr); 200 | 201 | /* Miscellaneous */ 202 | EXPORT ptr Stop_level_value(ptr); 203 | EXPORT void Sset_top_level_value(ptr, ptr); 204 | EXPORT void Slock_object(ptr); 205 | EXPORT void Sunlock_object(ptr); 206 | EXPORT int Slocked_objectp(ptr); 207 | EXPORT void Sforeign_symbol(const char *, void *); 208 | EXPORT void Sregister_symbol(const char *, void *); 209 | 210 | /* Support for calls into Scheme */ 211 | EXPORT ptr Scall0(ptr); 212 | EXPORT ptr Scall1(ptr, ptr); 213 | EXPORT ptr Scall2(ptr, ptr, ptr); 214 | EXPORT ptr Scall3(ptr, ptr, ptr, ptr); 215 | EXPORT void Sinitframe(iptr); 216 | EXPORT void Sput_arg(iptr, ptr); 217 | EXPORT ptr Scall(ptr, iptr); 218 | /* Warning: Sforeign_callable_entry_point(x) returns a pointer into x. */ 219 | #define Sforeign_callable_entry_point(x) ((void (*)(void))TO_VOIDP((uptr)(x)+65)) 220 | #define Sforeign_callable_code_object(x) ((ptr)TO_VOIDP((uptr)(x)-65)) 221 | 222 | /* Customization support. */ 223 | EXPORT const char * Skernel_version(void); 224 | EXPORT void Sretain_static_relocation(void); 225 | EXPORT void Sset_verbose(int); 226 | EXPORT void Sscheme_init(void (*)(void)); 227 | EXPORT void Sregister_boot_file(const char *); 228 | EXPORT void Sregister_boot_executable_relative_file(const char *, const char *); 229 | EXPORT void Sregister_boot_relative_file(const char *); 230 | EXPORT void Sregister_boot_file_fd(const char *, int); 231 | EXPORT void Sregister_boot_file_fd_region(const char *, int, iptr, iptr, int); 232 | EXPORT void Sregister_boot_file_bytes(const char *, void *, iptr); 233 | EXPORT void Sregister_heap_file(const char *); 234 | EXPORT void Scompact_heap(void); 235 | EXPORT void Ssave_heap(const char *, int); 236 | EXPORT void Sbuild_heap(const char *, void (*)(void)); 237 | EXPORT void Senable_expeditor(const char *); 238 | EXPORT int Sscheme_start(int, const char *[]); 239 | EXPORT int Sscheme_script(const char *, int, const char *[]); 240 | EXPORT int Sscheme_program(const char *, int, const char *[]); 241 | EXPORT void Sscheme_deinit(void); 242 | EXPORT void Sscheme_register_signal_registerer(void (*f)(int)); 243 | 244 | /* Thread support. */ 245 | EXPORT int Sactivate_thread(void); 246 | EXPORT void Sdeactivate_thread(void); 247 | EXPORT int Sdestroy_thread(void); 248 | 249 | /* Features. */ 250 | #define FEATURE_ICONV 251 | #define FEATURE_EXPEDITOR 252 | #define FEATURE_PTHREADS 253 | 254 | /* Locking macros. */ 255 | #define INITLOCK(addr) \ 256 | __asm__ __volatile__ ("movq $0, (%0)"\ 257 | : \ 258 | : "r" (addr) \ 259 | : "memory") 260 | 261 | #define SPINLOCK(addr) \ 262 | __asm__ __volatile__ ("0:\n\t"\ 263 | "movq $1, %%rax\n\t"\ 264 | "xchgq (%0), %%rax\n\t"\ 265 | "cmpq $0, %%rax\n\t"\ 266 | "je 2f\n\t"\ 267 | "1:\n\t"\ 268 | "pause\n\t"\ 269 | "cmpq $0, (%0)\n\t"\ 270 | "je 0b\n\t"\ 271 | "jmp 1b\n\t"\ 272 | "2:"\ 273 | : \ 274 | : "r" (addr) \ 275 | : "rax", "flags", "memory") 276 | 277 | #define UNLOCK(addr) \ 278 | __asm__ __volatile__ ("movq $0, (%0)"\ 279 | : \ 280 | : "r" (addr) \ 281 | :"memory") 282 | 283 | #define LOCKED_INCR(addr, ret) \ 284 | __asm__ __volatile__ ("lock; incq (%1)\n\t"\ 285 | "sete %b0\n\t"\ 286 | "movzx %b0, %0\n\t"\ 287 | : "=q" (ret) \ 288 | : "r" (addr) \ 289 | : "flags", "memory") 290 | 291 | #define LOCKED_DECR(addr, ret) \ 292 | __asm__ __volatile__ ("lock; decq (%1)\n\t"\ 293 | "sete %b0\n\t"\ 294 | "movzx %b0, %0\n\t"\ 295 | : "=q" (ret) \ 296 | : "r" (addr) \ 297 | : "flags", "memory") 298 | -------------------------------------------------------------------------------- /Lib/include/module.modulemap: -------------------------------------------------------------------------------- 1 | module RacketCS { 2 | header "racket.h" 3 | export * 4 | } -------------------------------------------------------------------------------- /Lib/include/racket.h: -------------------------------------------------------------------------------- 1 | #ifndef RACKET_H 2 | #define RACKET_H 3 | 4 | #if defined(__x86_64__) 5 | # include "chezscheme-x86_64-macos.h" 6 | #elif defined(__arm64__) 7 | # include "TargetConditionals.h" 8 | # if TARGET_OS_IPHONE 9 | # define _Nonnull 10 | # define _Nullable 11 | # include "chezscheme-arm64-ios.h" 12 | # else 13 | # include "chezscheme-arm64-macos.h" 14 | # endif 15 | #else 16 | # error "unsupported platform" 17 | #endif 18 | 19 | #include "racketcs.h" 20 | 21 | int racket_activate_thread() { 22 | return Sactivate_thread(); 23 | } 24 | 25 | void racket_deactivate_thread() { 26 | Sdeactivate_thread(); 27 | } 28 | 29 | int racket_destroy_thread() { 30 | return Sdestroy_thread(); 31 | } 32 | 33 | void racket_destroy() { 34 | return Sscheme_deinit(); 35 | } 36 | 37 | ptr _Nonnull racket_nil() { 38 | return Snil; 39 | } 40 | 41 | ptr _Nonnull racket_false() { 42 | return Sfalse; 43 | } 44 | 45 | ptr _Nonnull racket_true() { 46 | return Strue; 47 | } 48 | 49 | int racket_fixnump(ptr _Nullable p) { 50 | return Sfixnump(p); 51 | } 52 | 53 | ptr _Nullable racket_fixnum(iptr i) { 54 | return Sfixnum(i); 55 | } 56 | 57 | iptr racket_fixnum_value(ptr _Nullable p) { 58 | return Sfixnum_value(p); 59 | } 60 | 61 | ptr _Nullable racket_pointer(ptr _Nullable p) { 62 | return Sinteger((iptr)p); 63 | } 64 | 65 | ptr _Nonnull racket_symbol(const char * _Nonnull s) { 66 | return Sstring_to_symbol(s); 67 | } 68 | 69 | ptr _Nonnull racket_string(const char * _Nonnull s, uptr len) { 70 | return Sstring_utf8(s, len); 71 | } 72 | 73 | int racket_pairp(ptr _Nullable p) { 74 | return Spairp(p); 75 | } 76 | 77 | ptr _Nonnull racket_cons(ptr _Nullable a, ptr _Nullable b) { 78 | return Scons(a, b); 79 | } 80 | 81 | ptr _Nullable racket_car(ptr _Nonnull l) { 82 | return Scar(l); 83 | } 84 | 85 | ptr _Nullable racket_cdr(ptr _Nonnull l) { 86 | return Scdr(l); 87 | } 88 | 89 | int racket_procedurep(ptr _Nullable p) { 90 | return Sprocedurep(p); 91 | } 92 | 93 | int racket_bytevectorp(ptr _Nullable p) { 94 | return Sbytevectorp(p); 95 | } 96 | 97 | uptr racket_bytevector_length(ptr _Nonnull p) { 98 | return Sbytevector_length(p); 99 | } 100 | 101 | unsigned char * _Nonnull racket_bytevector_data(ptr _Nonnull p) { 102 | return (unsigned char *)Sbytevector_data(p); 103 | } 104 | 105 | void racket_lock_object(ptr _Nonnull o) { 106 | Slock_object(o); 107 | } 108 | 109 | void racket_unlock_object(ptr _Nonnull o) { 110 | Sunlock_object(o); 111 | } 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /Lib/include/racketcs.h: -------------------------------------------------------------------------------- 1 | /* include "chezscheme.h" before this file */ 2 | 3 | #ifndef RACKETCS_H 4 | #define RACKETCS_H 5 | 6 | #ifndef RACKET_API_EXTERN 7 | # define RACKET_API_EXTERN EXPORT 8 | #endif 9 | 10 | #ifndef RACKETCS_BOOT_H 11 | # define BOOT_EXTERN EXPORT 12 | # include "racketcsboot.h" 13 | #endif 14 | 15 | RACKET_API_EXTERN ptr racket_apply(ptr proc, ptr arg_list); 16 | 17 | RACKET_API_EXTERN ptr racket_primitive(const char *name); 18 | 19 | RACKET_API_EXTERN ptr racket_eval(ptr s_expr); 20 | RACKET_API_EXTERN ptr racket_dynamic_require(ptr module_path, ptr sym_or_false); 21 | RACKET_API_EXTERN void racket_namespace_require(ptr module_path); 22 | 23 | RACKET_API_EXTERN void racket_embedded_load_bytes(const char *code, uptr len, int as_predefined); 24 | RACKET_API_EXTERN void racket_embedded_load_file(const char *path, int as_predefined); 25 | RACKET_API_EXTERN void racket_embedded_load_file_region(const char *path, uptr start, uptr end, int as_predefined); 26 | 27 | RACKET_API_EXTERN void *racket_cpointer_address(ptr cptr); 28 | RACKET_API_EXTERN void *racket_cpointer_base_address(ptr cptr); 29 | RACKET_API_EXTERN iptr racket_cpointer_offset(ptr cptr); 30 | 31 | RACKET_API_EXTERN char *racket_get_self_exe_path(const char *argv0); 32 | RACKET_API_EXTERN char *racket_path_replace_filename(const char *path, const char *new_filename); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /Lib/include/racketcsboot.h: -------------------------------------------------------------------------------- 1 | #ifndef RACKETCS_BOOT_H 2 | #define RACKETCS_BOOT_H 3 | 4 | /* This structure type can change, but NULL/0 will be supported as a 5 | default for any new field that is added. */ 6 | typedef struct racket_boot_arguments_t { 7 | /* Boot files --- potentially the same path with different offsets. 8 | If a boot image is embedded in a larger file, it must be 9 | terminated with "\177". */ 10 | const char *boot1_path; /* REQUIRED unless `boot1_data`: path to "petite.boot" */ 11 | void *boot1_data; /* REQUIRED unless `boot1_path`: content of "petite.boot" */ 12 | long boot1_offset; 13 | long boot1_len; /* 0 => unknown length; REQUIRED non-0 when `boot1_data` */ 14 | const char *boot2_path; /* REQUIRED unless `boot2_data`: path to "scheme.boot" */ 15 | void *boot2_data; /* REQUIRED unless `boot2_path`: content of "scheme.boot" */ 16 | long boot2_offset; 17 | long boot2_len; /* 0 => unknown length; REQUIRED non-0 when `boot2_data` */ 18 | const char *boot3_path; /* REQUIRED unless `boot3_data`: path to "racket.boot" */ 19 | void *boot3_data; /* REQUIRED unless `boot3_path`: content of "racket.boot" */ 20 | long boot3_offset; 21 | long boot3_len; /* 0 => unknown length; REQUIRED non-0 when `boot3_data` */ 22 | 23 | /* Command-line arguments are handled in the same way as the 24 | `racket` exectuable. The `argv` array should *not* include the 25 | executable name like `argv` passed to `main`. */ 26 | int argc; 27 | char **argv; /* NULL => "-n", which does nothing after booting */ 28 | 29 | /* Racket path configuration, mostly setting the results of 30 | `(find-system-path ...)`: */ 31 | const char *exec_file; /* REQUIRED; usually the original argv[0] */ 32 | const char *run_file; /* can be NULL to mean the same as `exec_file` */ 33 | const char *collects_dir; /* can be NULL or "" to disable collection path */ 34 | const char *config_dir; /* use NULL or "etc" if you don't care */ 35 | /* wchar_t * */void *dll_dir; /* can be NULL for default */ 36 | const char *k_file; /* for -k; can be NULL for the same as `exec_file` */ 37 | 38 | /* How to initialize `use-compiled-file-paths`: */ 39 | int cs_compiled_subdir; /* true => subdirectory of "compiled" */ 40 | 41 | /* Embedded-code offset, which is added to any `-k` argument. */ 42 | long segment_offset; /* use 0 if no `-k` embedding */ 43 | 44 | /* For embedded DLLs on Windows, if non-NULL: */ 45 | void *dll_open; 46 | void *dll_find_object; 47 | void *dll_close; 48 | 49 | /* Whether to run as command-line Racket or in embedded mode: */ 50 | int exit_after; /* 1 => exit after handling the command-line */ 51 | 52 | /* For GUI applications; use 0 and "" as defaults: */ 53 | int is_gui; 54 | int wm_is_gracket_or_x11_arg_count; 55 | char *gracket_guid_or_x11_args; 56 | } racket_boot_arguments_t; 57 | 58 | BOOT_EXTERN void racket_boot(racket_boot_arguments_t *boot_args); 59 | 60 | /* Same as `racket_boot` prototype; but in type form: */ 61 | typedef void (*racket_boot_t)(racket_boot_arguments_t *boot_args); 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /Lib/libracketcs-arm64-ios.a: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:cd9e4b040dc900ee54523309fd62537a6962bf4d3c1faa288fe8cc21b4ff6544 3 | size 23898408 4 | -------------------------------------------------------------------------------- /Lib/libracketcs-arm64-iphonesimulator.a: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:ae7741dba4955240e4b9cd811a3217a697984134a4f749bb032e821b1d138826 3 | size 24032016 4 | -------------------------------------------------------------------------------- /Lib/libracketcs-arm64-macos.a: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:a223469882cb416b34430151375a9de409f9d4b75edbe0255b44630a4c7269e9 3 | size 1354472 4 | -------------------------------------------------------------------------------- /Lib/libracketcs-x86_64-macos.a: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:488b6abab13b1eed699f069d08f7f6eba9057c631612ea13d3da4a9eb66dabe0 3 | size 1616560 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: \ 3 | RacketCS-ios.xcframework \ 4 | RacketCS-macos.xcframework \ 5 | Tests/NoiseTest/Modules/mods.zo 6 | 7 | Lib/libracketcs-universal-macos.a: 8 | make -C Lib libracketcs-universal-macos.a 9 | 10 | RacketCS-ios.xcframework: Lib/include/* Lib/libracketcs-arm64-ios.a Lib/libracketcs-arm64-iphonesimulator.a 11 | rm -fr $@ 12 | xcodebuild -create-xcframework \ 13 | -library Lib/libracketcs-arm64-iphonesimulator.a -headers Lib/include \ 14 | -library Lib/libracketcs-arm64-ios.a -headers Lib/include \ 15 | -output $@ 16 | 17 | RacketCS-macos.xcframework: Lib/include/* Lib/libracketcs-universal-macos.a 18 | rm -fr $@ 19 | xcodebuild -create-xcframework \ 20 | -library Lib/libracketcs-universal-macos.a \ 21 | -headers Lib/include \ 22 | -output $@ 23 | 24 | Tests/NoiseTest/Modules/mods.zo: 25 | make -C Tests/NoiseTest/Modules mods.zo 26 | 27 | .PHONY: clean 28 | clean: 29 | rm -fr *.xcframework 30 | make -C Lib clean 31 | make -C Tests/NoiseTest/Modules clean 32 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "Noise", 6 | platforms: [ 7 | .iOS(.v14), 8 | .macOS(.v12), 9 | ], 10 | products: [ 11 | .library( 12 | name: "Noise", 13 | targets: ["Noise"] 14 | ), 15 | .library( 16 | name: "NoiseBackend", 17 | targets: ["NoiseBackend"] 18 | ), 19 | .library( 20 | name: "NoiseSerde", 21 | targets: ["NoiseSerde"] 22 | ), 23 | ], 24 | targets: [ 25 | .target( 26 | name: "NoiseBoot_iOS", 27 | resources: [.copy("boot")] 28 | ), 29 | .target( 30 | name: "NoiseBoot_macOS", 31 | resources: [.copy("boot")] 32 | ), 33 | .target( 34 | name: "Noise", 35 | dependencies: [ 36 | .target(name: "NoiseBoot_iOS", condition: .when(platforms: [.iOS])), 37 | .target(name: "NoiseBoot_macOS", condition: .when(platforms: [.macOS])), 38 | .target(name: "RacketCS-ios", condition: .when(platforms: [.iOS])), 39 | .target(name: "RacketCS-macos", condition: .when(platforms: [.macOS])), 40 | ], 41 | linkerSettings: [ 42 | .linkedLibrary("curses", .when(platforms: [.macOS])), 43 | .linkedLibrary("iconv"), 44 | ] 45 | ), 46 | .target( 47 | name: "NoiseBackend", 48 | dependencies: [ 49 | "Noise", 50 | "NoiseSerde" 51 | ] 52 | ), 53 | .target( 54 | name: "NoiseSerde" 55 | ), 56 | .testTarget( 57 | name: "NoiseTest", 58 | dependencies: [ 59 | "Noise", 60 | "NoiseBackend", 61 | "NoiseSerde", 62 | ], 63 | resources: [ 64 | .copy("Modules"), 65 | ] 66 | ), 67 | .binaryTarget( 68 | name: "RacketCS-ios", 69 | path: "RacketCS-ios.xcframework" 70 | ), 71 | .binaryTarget( 72 | name: "RacketCS-macos", 73 | path: "RacketCS-macos.xcframework" 74 | ), 75 | ] 76 | ) 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Noise 2 | 3 | Noise is a Swift wrapper around the [Racket] CS runtime intended to 4 | simplify embedding. See `Tests/NoiseTest/RacketTest.swift` for an 5 | example. 6 | 7 | ## Quickstart 8 | 9 | 1. Clone this repository. 10 | 2. Run `raco pkg install Racket/noise-serde{-lib,-doc}/`. 11 | 4. Run `make`. 12 | 13 | Note: [Git LFS][LFS] is used to store the binary files in `Lib/` and in 14 | `Sources/Noise/boot`, so you will need have [LFS] installed in order to 15 | pull those files. 16 | 17 | ## Usage 18 | 19 | The shared libraries and the boot files must match the version of Racket 20 | you use to compile your Racket code. Most likely, the versions of the 21 | files checked into the master branch _won't_ match your version of 22 | Racket, if you're using a release build of Racket. To import your own 23 | versions of these files, build Racket from source and run: 24 | 25 | ./Bin/copy-libs.sh arm64-macos /path/to/src/racket 26 | 27 | Where the first argument depends on your target OS and architecture: 28 | 29 | | OS | Architecture | Argument | 30 | |---------------|---------------|-------------------------| 31 | | macOS | x86_64 | `x86_64-macos` | 32 | | macOS | arm64/aarch64 | `arm64-macos` | 33 | | iOS | arm64/aarch64 | `arm64-ios` | 34 | | iOS Simulator | arm64/aarch64 | `arm64-iphonesimulator` | 35 | 36 | For iOS, you have to configure Racket with the following flags in order 37 | to generate a portable bytecode build: 38 | 39 | configure \ 40 | --host=aarch64-apple-darwin \ 41 | --enable-ios=iPhoneOS \ 42 | --enable-pb \ 43 | --enable-racket=auto \ 44 | --enable-libffi 45 | 46 | For the iPhone Simulator, change the value of the `--enable-ios` flag to 47 | `iPhoneSimulator`. After building for either platform, you need to merge 48 | the associated `libffi` archive into the generated `libracketcs.a`. For 49 | example: 50 | 51 | libtool -s \ 52 | -o racket/lib/libracketcs1.a \ 53 | racket/lib/libracketcs.a \ 54 | /path/to/libffi.a \ 55 | && mv racket/libracketcs{1,}.a 56 | 57 | Pre-compiled builds for recent versions of Racket are available on the 58 | following branches: 59 | 60 | * `racket-8.17` 61 | * `racket-8.16` 62 | * `racket-8.15` (first branch to include iOS build) 63 | * `racket-8.14` 64 | * `racket-8.13` 65 | * `racket-8.12` 66 | * `racket-8.11.1` 67 | * `racket-8.11` 68 | * `racket-8.10` 69 | 70 | See [NoiseBackendExample] for an example application built with Noise. 71 | 72 | ## NoiseSerde 73 | 74 | The `NoiseSerde` package and its associated `noise/serde` module (from 75 | `Racket/noise-serde-lib`) provide a way to define data structures that 76 | can automatically be shared (via serialization & deserialization) 77 | between Racket and Swift. 78 | 79 | To use `NoiseSerde` from Racket, you will have to install 80 | `noise-serde-lib`: 81 | 82 | raco pkg install Racket/noise-serde-lib/ 83 | 84 | You may also want to install its docs: 85 | 86 | raco pkg install Racket/noise-serde-doc/ 87 | 88 | Run `raco docs noise` to read the docs. 89 | 90 | ## NoiseBackend 91 | 92 | The `NoiseBackend` package and its associated `noise/backend` module 93 | build upon `NoiseSerde` to provide a client-server implementation 94 | where the Racket server is continuously run in a background thread and 95 | the Swift client communicates with it via pipes. 96 | 97 | ## License 98 | 99 | Noise and its associated packages are licensed under the 3-Clause BSD license. 100 | 101 | See [this page][racket-license] for information on Racket's license. 102 | 103 | [NoiseBackendExample]: https://github.com/Bogdanp/NoiseBackendExample 104 | [Racket]: https://racket-lang.org 105 | [LFS]: https://git-lfs.github.com 106 | [racket-license]: https://github.com/racket/racket/blob/82ca0f76f2e18f242db742991596eb509ce49cc1/LICENSE.txt 107 | -------------------------------------------------------------------------------- /Racket/noise-serde-doc/info.rkt: -------------------------------------------------------------------------------- 1 | #lang info 2 | 3 | (define license 'BSD-3-Clause) 4 | (define collection "noise") 5 | (define deps '("base")) 6 | (define build-deps '("base" 7 | "noise-serde-lib" 8 | "racket-doc" 9 | "scribble-lib")) 10 | (define update-implies '("noise-serde-lib")) 11 | (define scribblings '(("noise-manual.scrbl"))) 12 | -------------------------------------------------------------------------------- /Racket/noise-serde-doc/noise-manual.scrbl: -------------------------------------------------------------------------------- 1 | #lang scribble/manual 2 | 3 | @(require scribble/example 4 | (for-label (only-in ffi/unsafe ctype?) 5 | noise/backend 6 | noise/serde 7 | noise/unsafe/callout 8 | racket/base 9 | racket/contract)) 10 | 11 | @title{Noise Ser/de} 12 | @author[(author+email "Bogdan Popa" "bogdan@defn.io")] 13 | 14 | @(define (noise-anchor . content) 15 | (apply link "https://github.com/Bogdanp/Noise" content)) 16 | 17 | This is a companion package to @noise-anchor{Noise} that provides 18 | utilities for serializing and deserializing data structures between 19 | Swift and Racket. 20 | 21 | @(define ev 22 | (let ([ev (make-base-eval)]) 23 | (begin0 ev 24 | (ev '(require noise/backend noise/serde racket/contract))))) 25 | 26 | @section[#:tag "serde"]{Serialization & Deserialization} 27 | @defmodule[noise/serde] 28 | 29 | @subsection{Records} 30 | 31 | A @deftech{record} is a data structure that is shared between Swift 32 | and Racket. In both languages, they are represented by structs. Use 33 | the @tt{raco} command @tt{noise-serde-codegen} to generate Swift 34 | definitions for records reachable from a given root module. 35 | 36 | @deftogether[( 37 | @defidform[:] 38 | @defform[ 39 | #:literals (:) 40 | (define-record name 41 | field ...) 42 | #:grammar ([name (code:line id) 43 | (id : protocol-id ...+)] 44 | [field [field-id : field-type field-option ...] 45 | [(field-id default-expr) : field-type field-option ...]] 46 | [field-option (code:line #:mutable) 47 | (code:line #:contract field-ctc-expr)]) 48 | #:contracts ([field-type (or/c field-type? enum-info? record-info?)])] 49 | )]{ 50 | 51 | Defines a record called @racket[name] with the given set of 52 | @racket[field]s. Records are backed by structs and generate smart 53 | constructors that take a keyword argument for every field. Smart 54 | constructors are named by prepending @tt{make-} to the record name 55 | and bound at phase level 0. Record @racket[name]s must be unique 56 | across all modules. 57 | 58 | When a field is @racket[#:mutable], it uses @tt{var} as its 59 | introducer in Swift instead of @tt{let}. The option currently has 60 | no effect on the generated Racket code. 61 | 62 | @examples[ 63 | #:eval ev 64 | (define-record (Human : Equatable Hashable) 65 | [name : String] 66 | [age : UVarint #:contract (integer-in 0 125)] 67 | [(likes-pizza? #t) : Bool]) 68 | (make-Human 69 | #:name "Bogdan" 70 | #:age 30) 71 | Human 72 | ] 73 | 74 | @history[ 75 | #:changed "0.8" @elem{Added protocol support.} 76 | #:changed "0.3" @elem{Added the @racket[#:mutable] field option.} 77 | ] 78 | } 79 | 80 | @defform[(record-out id)]{ 81 | Exports the bindings associated with a record @racket[id]. 82 | } 83 | 84 | @defproc[(record-info? [v any/c]) boolean?]{ 85 | Returns @racket[#t] when @racket[v] is a value containing runtime 86 | information about a @tech{record}. 87 | } 88 | 89 | 90 | @subsection{Enumerations} 91 | 92 | An @deftech{enumeration} is a tagged union of product types. In 93 | Racket, enum variants are represented by individual structs that 94 | inherit from a common base. In Swift, they are represented using 95 | regular enums. 96 | 97 | @defform[ 98 | #:literals (:) 99 | (define-enum name 100 | [variant-name variant-field ...] ...+) 101 | #:grammar ([name (code:line id) 102 | (id : protocol-id ...+)] 103 | [variant-field {field-id : field-type}]) 104 | #:contracts ([field-type (or/c field-type? enum-info? record-info?)])]{ 105 | 106 | Defines an enumeration called @racket[name] with the given set of 107 | variants. Enumeration @racket[name]s must be unique across all 108 | modules. In Swift, the @racket[variant-name]s and 109 | @racket[field-id]s are converted to camel case. 110 | 111 | @examples[ 112 | #:eval ev 113 | (define-enum Result 114 | [ok] 115 | [err {message : String}]) 116 | (Result? (Result.ok)) 117 | (Result? (Result.err "example")) 118 | Result 119 | ] 120 | 121 | @history[ 122 | #:changed "0.8" @elem{Added protocol support.} 123 | ] 124 | } 125 | 126 | @defform[(enum-out id)]{ 127 | Exports the bindings associated with an enum @racket[id]. 128 | } 129 | 130 | @defproc[(enum-info? [v any/c]) boolean?]{ 131 | Returns @racket[#t] when @racket[v] is a value containing runtime 132 | information about an @tech{enumeration}. 133 | } 134 | 135 | 136 | @subsection{Field Types} 137 | 138 | @deftech{Field types} control how individual values are serialized and 139 | deserialized. 140 | 141 | @defproc[(field-type? [v any/c]) boolean?]{ 142 | Returns @racket[#t] when @racket[v] is a @tech{field type}. 143 | } 144 | 145 | @deftogether[( 146 | @defthing[Bool field-type?] 147 | @defthing[Bytes field-type?] 148 | @defthing[Float32 field-type?] 149 | @defthing[Float64 field-type?] 150 | @defthing[Int16 field-type?] 151 | @defthing[Int32 field-type?] 152 | @defthing[Varint field-type?] 153 | @defthing[UInt16 field-type?] 154 | @defthing[UInt32 field-type?] 155 | @defthing[UVarint field-type?] 156 | @defthing[String field-type?] 157 | @defthing[Symbol field-type?] 158 | )]{ 159 | 160 | @tech{Field types} for primitive values. 161 | 162 | The @racket[Varint] and @racket[UVarint] field types serialize 163 | signed and unsigned integer values, respectively, using a 164 | variable-length encoding. In Swift, these values are represented by 165 | @tt{Int64} and @tt{UInt64}. 166 | } 167 | 168 | @defform[(Delay t-expr) 169 | #:contracts ([t-expr (or/c field-type? enum-info? record-info?)])]{ 170 | A constructor for a field type that delays the execution of 171 | @racket[t-expr] until one of its methods is called. Use this to 172 | implement mutually-recursive data types. 173 | } 174 | 175 | @defproc[(HashTable [k (or/c field-type? enum-info? record-info?)] 176 | [v (or/c field-type? enum-info? record-info?)]) field-type?]{ 177 | A constructor for @tech{field types} that represent hash tables 178 | composed of @racket[k] keys and @racket[v] values. In Swift, these 179 | values are represented by @tt{Dictionary} values parameterized over 180 | the Swift representations of the @racket[k] and @racket[v] types, 181 | respectively. 182 | 183 | When @racket[k] is an enum or a record type, the enum or record must 184 | be extended to implement the @tt{Hashable} protocol in Swift. 185 | } 186 | 187 | @defproc[(Listof [t (or/c field-type? enum-info? record-info?)]) field-type?]{ 188 | A constructor for @tech{field types} that represent lists composed 189 | of @racket[field-type] values. In Swift, these values are 190 | represented by arrays of the subtype. 191 | } 192 | 193 | @defproc[(Optional [t (or/c field-type? enum-info? record-info?)]) field-type?]{ 194 | A constructor for optional @tech{field types}. 195 | } 196 | 197 | @defproc[(StringConvertible [string-> (-> string? any/c)] 198 | [->string (-> any/c string?)]) field-type?]{ 199 | Like @racket[String], but converts the value to a string using 200 | @racket[->string] before sending it to a client and converts strings 201 | to values using @racket[string->] when receiving data from a client. 202 | } 203 | 204 | 205 | @section[#:tag "backends"]{Backends} 206 | @defmodule[noise/backend] 207 | 208 | The @racketmodname[noise/backend] module has an internal 209 | @deftech{handler registry} that is used to map remote procedure call 210 | ids to handler procedures. 211 | 212 | @defform[ 213 | #:literals (:) 214 | (define-rpc (id arg ... maybe-response-type) 215 | body ...+) 216 | #:grammar [(arg [arg-label arg-id : arg-type-expr]) 217 | (maybe-response-type (code:line) 218 | (code:line : response-type-expr))] 219 | #:contracts ([arg-type-expr (or/c field-type? enum-info? record-info?)] 220 | [response-type-expr (or/c field-type? enum-info? record-info?)]) 221 | ]{ 222 | Defines a procedure named @racket[id] and registers an RPC handler for 223 | it in the @tech{handler registry}. RPC @racket[id]s must be unique 224 | across all modules. The procedure is automatically provided in a 225 | submodule of the enclosing module named @racket[rpc]. 226 | 227 | The @tt{noise-serde-codegen} command automatically generates 228 | Swift code to handle calling these procedures. In Swift, the RPC 229 | @racket[id], @racket[arg-label]s and @racket[arg-id]s are converted to 230 | camel case. The @racket[arg-label]s have no meaning in Racket. 231 | 232 | @examples[ 233 | #:eval ev 234 | (define-rpc (do-nothing) 235 | (void)) 236 | (do-nothing) 237 | (define-rpc (get-human-name [of h : Human] : String) 238 | (Human-name h)) 239 | (get-human-name (make-Human #:name "Bogdan" #:age 30)) 240 | ] 241 | } 242 | 243 | @defform[ 244 | #:literals (:) 245 | (define-callout (id arg ...)) 246 | #:grammar [(arg [arg-id : arg-type-expr])] 247 | #:contracts ([arg-type-expr (or/c field-type? enum-info? record-info?)]) 248 | ]{ 249 | Defines a foreign procedure named @racket[id]. Callout @racket[id]s 250 | must be unique across all modules. 251 | 252 | The @tt{noise-serde-codegen} command automatically generates Swift 253 | code to handle installing Swift procedures for each callout. 254 | 255 | @examples[ 256 | #:eval ev 257 | (define-callout (hello-cb [h : Human])) 258 | ] 259 | 260 | In Racket, the above example binds a procedure named @racket[hello] 261 | that may be called with a @racket[Human] value in order to execute a 262 | Swift procedure. In Swift, the generated backend will contain a 263 | procedure with the following signature: 264 | 265 | @verbatim{installCallback(helloCb: @"@"escaping (Human) -> Void) -> Future} 266 | 267 | That procedure can be used to install a callback from the Swift 268 | side. Executing a callout on the Racket side before it's been 269 | installed from the Swift side raises an exception. 270 | 271 | Currently, the buffer used to decode data sent back to Swift via 272 | a callout is limited to 8KiB, so avoid sending large payloads. If 273 | necessary, have the Swift side call a regular RPC when it receives a 274 | callout instead. 275 | } 276 | 277 | @defproc[(serve [in-fd exact-integer?] 278 | [out-fd exact-integer?]) (-> void?)]{ 279 | 280 | Converts the file descriptors represented by @racket[in-fd] and 281 | @racket[out-fd] to an input port and an output port, respectively, 282 | then spawns a thread that reads requests from the input port in the 283 | form of @tech{records}. Request handlers are defined using 284 | @racket[define-rpc]. Handlers are run in their own threads and 285 | multiple requests may be handled concurrently. 286 | 287 | Returns a procedure that stops the server when applied. 288 | } 289 | 290 | 291 | @section[#:tag "callouts"]{Callouts} 292 | @defmodule[noise/unsafe/callout] 293 | 294 | The @racketmodname[noise/unsafe/callout] module provides a facility for 295 | converting function pointer addresses to callable Racket procedures via 296 | the FFI. A @deftech{callout box} is a two-element struct containing 297 | a C function type and an optional Racket procedure of that type. 298 | Callout boxes start out empty and must be filled via a call to 299 | @racket[callout-box-install!]. Callout boxes are themselves callable 300 | once filled. 301 | 302 | @emph{Warning:} these operations are inherently unsafe and you must take 303 | care that the function pointers installed in a box are kept immobile 304 | during the lifetime of that box. 305 | 306 | @defproc[(callout-box? [v any/c]) boolean?]{ 307 | Returns @racket[#t] when @racket[v] is a @tech{callout box}. 308 | } 309 | 310 | @defproc[(make-callout-box [fun-type ctype?]) callout-box?]{ 311 | Returns a @tech{callout box} with the given function type. 312 | } 313 | 314 | @defproc[(callout-box-install! [b callout-box?] 315 | [p exact-integer?]) void?]{ 316 | 317 | Installs the function pointer located at address @racket[p] in 318 | @racket[b]. 319 | } 320 | -------------------------------------------------------------------------------- /Racket/noise-serde-lib/.gitignore: -------------------------------------------------------------------------------- 1 | compiled/ 2 | -------------------------------------------------------------------------------- /Racket/noise-serde-lib/backend.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require ffi/unsafe/port 4 | racket/match 5 | racket/port 6 | "private/backend.rkt" 7 | "private/callout.rkt" 8 | "private/debug.rkt" 9 | "private/serde.rkt" 10 | "unsafe/callout.rkt") 11 | 12 | (provide 13 | define-callout 14 | define-rpc 15 | serve) 16 | 17 | (define (serve in-fd out-fd) 18 | (define cust (make-custodian)) 19 | (define thd 20 | (parameterize ([current-custodian cust]) 21 | (define server-in 22 | (make-debug-input-port 23 | (unsafe-file-descriptor->port in-fd 'in '(read)))) 24 | (define server-out 25 | (make-debug-output-port 26 | (unsafe-file-descriptor->port out-fd 'out '(write)))) 27 | (thread/suspend-to-kill 28 | (lambda () 29 | (let loop () 30 | (sync 31 | (handle-evt 32 | (thread-receive-evt) 33 | (lambda (_) 34 | (match (thread-receive) 35 | ['(stop) 36 | (close-input-port server-in) 37 | (close-output-port server-out)] 38 | [`(response ,id ,response-type ,response-data) 39 | (log-noise-debug "<~a: ~.v" id response-data) 40 | (write-uvarint id server-out) 41 | (if (exn:fail? response-data) 42 | (write-error response-data server-out) 43 | (write-data response-type response-data server-out)) 44 | (flush-output server-out) 45 | (loop)] 46 | [msg 47 | (log-noise-warning "backend/serve invalid message: ~e" msg)]))) 48 | (handle-evt 49 | server-in 50 | (lambda (in) 51 | (with-handlers ([exn:fail? 52 | (lambda (e) 53 | ((error-display-handler) 54 | (format "backend/serve: ~a" (exn-message e)) 55 | e))]) 56 | (define req-id (read-uvarint in)) 57 | (define rpc-id (read-uvarint in)) 58 | (match-define (rpc-info _id rpc-name rpc-args response-type handler) 59 | (hash-ref rpc-infos rpc-id)) 60 | (define args 61 | (for/list ([ra (in-list rpc-args)]) 62 | (read-field (rpc-arg-type ra) in))) 63 | (log-noise-debug ">~a: ~.v" req-id (cons rpc-name args)) 64 | (define request-cust 65 | (make-custodian)) 66 | (define request-thd 67 | (parameterize ([current-custodian request-cust]) 68 | (thread 69 | (lambda () 70 | (define response-data 71 | (with-handlers ([exn:fail? 72 | (lambda (e) 73 | (begin0 e 74 | ((error-display-handler) 75 | (format "backend/handler: ~a" (exn-message e)) 76 | e)))]) 77 | (apply handler args))) 78 | (thread-resume thd (current-thread)) 79 | (thread-send thd `(response ,req-id ,response-type ,response-data)))))) 80 | (thread 81 | (lambda () 82 | (thread-wait request-thd) 83 | (custodian-shutdown-all request-cust)))) 84 | (loop))))))))) 85 | (lambda () 86 | (thread-resume thd (current-thread)) 87 | (thread-send thd '(stop)) 88 | (thread-wait thd) 89 | (custodian-shutdown-all cust))) 90 | 91 | (define (write-error e out) 92 | (write-byte 0 out) 93 | (write-field String (~stacktrace e) out)) 94 | 95 | ;; Use a background thread to write the data in order to try and catch 96 | ;; any errors that occur during writing without having to buffer writes 97 | ;; into Racket memory before sending them over to the client. 98 | (define (write-data type data [out (current-output-port)]) 99 | (define err-ch (make-channel)) 100 | (define-values (pipe-in pipe-out) 101 | (make-pipe (* 1 1024 1024))) 102 | (define write-thd 103 | (thread 104 | (lambda () 105 | (with-handlers ([exn:fail? 106 | (lambda (e) 107 | (close-output-port pipe-out) 108 | (channel-put err-ch e))]) 109 | (unless (eq? type Void) 110 | (write-field type data pipe-out)) 111 | (close-output-port pipe-out))))) 112 | (let write-loop ([status-sent? #f]) 113 | (sync 114 | (handle-evt 115 | err-ch 116 | (lambda (e) 117 | (when status-sent? 118 | ;; We've already written some response data, so we MUST crash 119 | ;; in order to avoid having our response be misinterpreted. 120 | (exit e)) 121 | (write-error e out))) 122 | (handle-evt 123 | write-thd 124 | (lambda (_) 125 | (unless status-sent? 126 | (write-byte 1 out)) 127 | (copy-port pipe-in out))) 128 | (handle-evt 129 | pipe-in 130 | (lambda (_) 131 | (unless status-sent? 132 | (write-byte 1 out)) 133 | (copy-port pipe-in out) 134 | (write-loop #t))))) 135 | (close-input-port pipe-in)) 136 | 137 | (define (~stacktrace e) 138 | (call-with-output-string 139 | (lambda (out) 140 | (parameterize ([current-error-port out]) 141 | ((error-display-handler) 142 | (exn-message e) 143 | e))))) 144 | 145 | (module+ test 146 | (require rackunit) 147 | (define (response-bytes type data) 148 | (with-output-to-bytes 149 | (lambda () 150 | (write-data type data)))) 151 | (check-equal? 152 | (response-bytes UInt32 1) 153 | #"\1\0\0\0\1") 154 | (check-equal? 155 | (response-bytes String "hello") 156 | #"\1\nhello") 157 | (check-true 158 | (regexp-match? 159 | #rx#"string->bytes/utf-8: contract violation" 160 | (response-bytes String #f))) 161 | (check-equal? 162 | (response-bytes (Optional String) #f) 163 | #"\1\0")) 164 | 165 | 166 | ;; callout ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 167 | 168 | (define-rpc (install-callback [internal-with-id id : UVarint] 169 | [and-addr addr : Varint]) 170 | (define cbox (callout-info-cbox (hash-ref callout-infos id))) 171 | (callout-box-install! cbox addr)) 172 | -------------------------------------------------------------------------------- /Racket/noise-serde-lib/codegen.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require racket/format 4 | racket/match 5 | racket/string 6 | threading 7 | "private/backend.rkt" 8 | "private/callout.rkt" 9 | "private/serde.rkt") 10 | 11 | (provide 12 | current-write-backend-code? 13 | write-Swift-code) 14 | 15 | (define current-write-backend-code? 16 | (make-parameter #t)) 17 | 18 | (define (swift-type t) 19 | ((field-type-swift-proc t))) 20 | 21 | (define (~hex n) 22 | (~a "0x" (~a #:min-width 4 #:left-pad-string "0" #:align 'right (number->string n 16)))) 23 | 24 | (define (~name id) 25 | (~> (symbol->string id) 26 | (regexp-replace* #rx"\\?" _ "Huh") 27 | (regexp-replace* #rx"-([a-z])" _ (λ (_ start) (string-upcase start))))) 28 | 29 | (define (write-Swift-code [out (current-output-port)]) 30 | (define write-backend-code? 31 | (current-write-backend-code?)) 32 | 33 | (fprintf out "// This file was automatically generated by noise-serde-lib.~n") 34 | (fprintf out "import Foundation~n") 35 | (when write-backend-code? 36 | (fprintf out "import NoiseBackend~n")) 37 | (fprintf out "import NoiseSerde~n") 38 | 39 | (for ([id (in-list (sort (hash-keys enum-infos) <) )]) 40 | (define e (hash-ref enum-infos id)) 41 | (fprintf out "~n") 42 | (write-enum-code e out)) 43 | 44 | (for ([id (in-list (sort (hash-keys record-infos) <))]) 45 | (define r (hash-ref record-infos id)) 46 | (fprintf out "~n") 47 | (write-record-code r out)) 48 | 49 | (when write-backend-code? 50 | (fprintf out "~n") 51 | (write-backend-code out))) 52 | 53 | (define (write-enum-code e [out (current-output-port)]) 54 | (match-define (enum-info _id name protocols variants) e) 55 | (define ~protocols 56 | (let ([protocols (append protocols '(Readable Sendable Writable))]) 57 | (string-join (map symbol->string protocols) ", "))) 58 | (fprintf out "public enum ~a: ~a {~n" name ~protocols) 59 | (for ([v (in-vector variants)]) 60 | (match-define (enum-variant _id name _constructor fields) v) 61 | (cond 62 | [(null? fields) 63 | (fprintf out " case ~a~n" (~name name))] 64 | [else 65 | (define fields-str 66 | (string-join 67 | (for/list ([f (in-list fields)]) 68 | (swift-type (enum-variant-field-type f))) 69 | ", ")) 70 | (fprintf out " case ~a(~a)~n" (~name name) fields-str)])) 71 | 72 | (fprintf out "~n") 73 | (fprintf out " public static func read(from inp: InputPort, using buf: inout Data) -> ~a {~n" name) 74 | (fprintf out " let tag = UVarint.read(from: inp, using: &buf)~n") 75 | (fprintf out " switch tag {~n") 76 | (for ([v (in-vector variants)]) 77 | (match-define (enum-variant id name _constructor fields) v) 78 | (fprintf out " case ~a:~n" (~hex id)) 79 | (cond 80 | [(null? fields) 81 | (fprintf out " return .~a~n" (~name name))] 82 | [else 83 | (fprintf out " return .~a(~n" (~name name)) 84 | (define len (length fields)) 85 | (for ([(f idx) (in-indexed (in-list fields))]) 86 | (define last? (= idx (sub1 len))) 87 | (define maybe-comma (if last? "" ",")) 88 | (define type (swift-type (enum-variant-field-type f))) 89 | (fprintf out " ~a.read(from: inp, using: &buf)~a~n" type maybe-comma)) 90 | (fprintf out " )~n")])) 91 | (fprintf out " default:~n") 92 | (fprintf out " preconditionFailure(\"~a: unexpected tag \\(tag)\")~n" name) 93 | (fprintf out " }~n") 94 | (fprintf out " }~n") 95 | 96 | (fprintf out "~n") 97 | (fprintf out " public func write(to out: OutputPort) {~n") 98 | (fprintf out " switch self {~n") 99 | (for ([v (in-vector variants)]) 100 | (match-define (enum-variant id name _constructor fields) v) 101 | (define field-names 102 | (map (compose1 ~name enum-variant-field-name) fields)) 103 | (define binders-str 104 | (if (null? field-names) 105 | "" 106 | (format "(~a)" (string-join 107 | (for/list ([name (in-list field-names)]) 108 | (format "let ~a" name)) 109 | ", ")))) 110 | (fprintf out " case .~a~a:~n" (~name name) binders-str) 111 | (fprintf out " UVarint(~a).write(to: out)~n" (~hex id)) 112 | (for ([name (in-list field-names)]) 113 | (fprintf out " ~a.write(to: out)~n" name))) 114 | (fprintf out " }~n") 115 | (fprintf out " }~n") 116 | 117 | (fprintf out "}~n")) 118 | 119 | (define (write-record-code r [out (current-output-port)]) 120 | (match-define (record-info _id name _constructor protocols fields) r) 121 | (define ~protocols 122 | (let ([protocols (append protocols '(Readable Sendable Writable))]) 123 | (string-join (map symbol->string protocols) ", "))) 124 | (fprintf out "public struct ~a: ~a {~n" name ~protocols) 125 | (for ([f (in-list fields)]) 126 | (fprintf out 127 | " public ~a ~a: ~a~n" 128 | (if (record-field-mutable? f) "var" "let") 129 | (~name (record-field-id f)) 130 | (swift-type (record-field-type f)))) 131 | 132 | (fprintf out "~n") 133 | (fprintf out " public init(~n") 134 | (define len (length fields)) 135 | (for ([(f idx) (in-indexed (in-list fields))]) 136 | (define last? (= idx (sub1 len))) 137 | (define maybe-comma (if last? "" ",")) 138 | (define id (record-field-id f)) 139 | (define type (swift-type (record-field-type f))) 140 | (fprintf out " ~a: ~a~a~n" (~name id) type maybe-comma)) 141 | (fprintf out " ) {~n") 142 | (for ([f (in-list fields)]) 143 | (define id (record-field-id f)) 144 | (define camel-id (~name id)) 145 | (fprintf out " self.~a = ~a~n" camel-id camel-id)) 146 | (fprintf out " }~n") 147 | 148 | (fprintf out "~n") 149 | (fprintf out " public static func read(from inp: InputPort, using buf: inout Data) -> ~a {~n" name) 150 | (fprintf out " return ~a(~n" name) 151 | (for ([(f idx) (in-indexed (in-list fields))]) 152 | (define last? (= idx (sub1 len))) 153 | (define maybe-comma (if last? "" ",")) 154 | (define id (record-field-id f)) 155 | (define camel-id (~name id)) 156 | (define type (swift-type (record-field-type f))) 157 | (fprintf out " ~a: ~a.read(from: inp, using: &buf)~a~n" camel-id type maybe-comma)) 158 | (fprintf out " )~n") 159 | (fprintf out " }~n") 160 | 161 | (fprintf out "~n") 162 | (fprintf out " public func write(to out: OutputPort) {~n") 163 | (for ([f (in-list fields)]) 164 | (define camel-id (~name (record-field-id f))) 165 | (fprintf out " ~a.write(to: out)~n" camel-id)) 166 | (fprintf out " }~n") 167 | 168 | (fprintf out "}~n")) 169 | 170 | (define (write-backend-code out) 171 | (fprintf out "public final class Backend: Sendable {~n") 172 | (fprintf out " let impl: NoiseBackend.Backend!~n~n") 173 | (fprintf out " init(withZo zo: URL, andMod mod: String, andProc proc: String) {~n") 174 | (fprintf out " impl = NoiseBackend.Backend(withZo: zo, andMod: mod, andProc: proc)~n") 175 | (fprintf out " }~n") 176 | 177 | (define sorted-rpc-ids (sort (hash-keys rpc-infos) <)) 178 | (for ([id (in-list sorted-rpc-ids)]) 179 | (match-define (rpc-info _ name args type _proc) 180 | (hash-ref rpc-infos id)) 181 | (define args-str 182 | (string-join 183 | (for/list ([arg (in-list args)]) 184 | (match-define (rpc-arg label name type) arg) 185 | (define formatted-label (~name label)) 186 | (define formatted-name (~name name)) 187 | (define formatted-type (swift-type type)) 188 | (if (equal? formatted-label formatted-name) 189 | (format "~a: ~a" formatted-label formatted-type) 190 | (format "~a ~a: ~a" formatted-label formatted-name formatted-type))) 191 | ", ")) 192 | (define arg-pairs-str 193 | (string-join 194 | (for/list ([arg (in-list args)]) 195 | (match-define (rpc-arg label name _type) arg) 196 | (if (eq? label '_) 197 | (~name name) 198 | (format "~a: ~a" 199 | (~name label) 200 | (~name name)))) 201 | ", ")) 202 | (fprintf out "~n") 203 | (fprintf out " public func ~a(~a) -> Future {~n" (~name name) args-str (swift-type type)) 204 | (fprintf out " return impl.send(~n") 205 | (fprintf out " writeProc: { (out: OutputPort) in~n") 206 | (fprintf out " UVarint(~a).write(to: out)~n" (~hex id)) 207 | (for ([arg (in-list args)]) 208 | (match-define (rpc-arg _label name _type) arg) 209 | (fprintf out " ~a.write(to: out)~n" (~name name))) 210 | (fprintf out " },~n") 211 | (cond 212 | [(eq? type Void) 213 | (fprintf out " readProc: { (inp: InputPort, buf: inout Data) -> Void in }~n")] 214 | [else 215 | (fprintf out " readProc: { (inp: InputPort, buf: inout Data) -> ~a in~n" (swift-type type)) 216 | (fprintf out " return ~a.read(from: inp, using: &buf)~n" (swift-type type)) 217 | (fprintf out " }~n")]) 218 | (fprintf out " )~n") 219 | (fprintf out " }~n") 220 | (fprintf out "~n") 221 | (fprintf out " public func ~a(~a) async throws -> ~a {~n" (~name name) args-str (swift-type type)) 222 | (fprintf out " return try await FutureUtil.asyncify(~a(~a))~n" (~name name) arg-pairs-str) 223 | (fprintf out " }~n")) 224 | 225 | (define sorted-callout-ids (sort (hash-keys callout-infos) <)) 226 | (for ([id (in-list sorted-callout-ids)]) 227 | (match-define (callout-info _ name args _cbox) 228 | (hash-ref callout-infos id)) 229 | (define proc-name (~name name)) 230 | (define proc-type 231 | (format "@escaping @Sendable (~a) -> Void" 232 | (string-join 233 | (map (compose1 swift-type callout-arg-type) args) 234 | ", "))) 235 | (fprintf out "~n") 236 | (fprintf out " public func installCallback(~a proc: ~a) -> Future {~n" proc-name proc-type) 237 | (fprintf out " return NoiseBackend.installCallback(id: ~a, rpc: self.installCallback(internalWithId:andAddr:)) { inp in~n" id) 238 | (fprintf out " var buf = Data(count: 8*1024)~n") 239 | (fprintf out " proc(~n") 240 | (define last-idx (sub1 (length args))) 241 | (for ([(arg idx) (in-indexed (in-list args))]) 242 | (match-define (callout-arg _name type) arg) 243 | (define maybe-comma (if (= idx last-idx) "" ",")) 244 | (fprintf out " ~a.read(from: inp, using: &buf)~a~n" (swift-type type) maybe-comma)) 245 | (fprintf out " )~n") 246 | (fprintf out " }~n") 247 | (fprintf out " }~n")) 248 | 249 | (fprintf out "}~n")) 250 | 251 | (module+ main 252 | (require racket/cmdline) 253 | (command-line 254 | #:once-each 255 | [("--no-backend") 256 | "turn off backend code generation" 257 | (current-write-backend-code? #f)] 258 | #:args [modpath] 259 | (parameterize ([current-output-port (current-error-port)]) 260 | (dynamic-require modpath #f))) 261 | (write-Swift-code)) 262 | -------------------------------------------------------------------------------- /Racket/noise-serde-lib/info.rkt: -------------------------------------------------------------------------------- 1 | #lang info 2 | 3 | (define license 'BSD-3-Clause) 4 | (define version "0.10") 5 | (define collection "noise") 6 | (define deps '("base" 7 | "threading-lib")) 8 | (define build-deps '("rackunit-lib")) 9 | (define raco-commands 10 | '(("noise-serde-codegen" (submod noise/codegen main) "generate Noise ser/de code" #f))) 11 | -------------------------------------------------------------------------------- /Racket/noise-serde-lib/private/backend.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require (for-syntax racket/base 4 | syntax/parse/pre 5 | "common.rkt") 6 | "sequencer.rkt" 7 | "serde.rkt") 8 | 9 | (provide 10 | define-rpc 11 | 12 | rpc-infos 13 | (struct-out rpc-arg) 14 | (struct-out rpc-info)) 15 | 16 | (struct rpc-arg (label name type)) 17 | (struct rpc-info ([id #:mutable] name args response-type proc)) 18 | 19 | (define rpc-infos (make-hasheqv)) 20 | (define rpc-info-sequencer 21 | (make-sequencer 22 | rpc-infos 23 | rpc-info-name 24 | set-rpc-info-id!)) 25 | 26 | (begin-for-syntax 27 | (define-syntax-class arg 28 | #:literals (:) 29 | (pattern [name:id : type:expr] #:with label #'name) 30 | (pattern [label:id name:id : type:expr]))) 31 | 32 | (define-syntax (define-rpc stx) 33 | (syntax-parse stx 34 | #:literals (:) 35 | [(_ (name:id arg:arg ... {~optional {~seq : type:expr}}) body ...+) 36 | #:fail-unless (valid-name-stx? #'name) 37 | "RPC names may only contain alphanumeric characters, dashes and underscores" 38 | #:fail-unless (andmap valid-name-stx? (syntax-e #'(arg.name ...))) 39 | "RPC labels may only contain alphanumeric characters, dashes and underscores" 40 | #`(begin 41 | (define response-type 42 | {~? (->field-type 'Backend type) Void}) 43 | (unless (field-type? response-type) 44 | (error 'define-rpc "~e is not a valid response type~n in: ~a" response-type 'name)) 45 | (define (name arg.name ...) 46 | body ...) 47 | (define args 48 | (for/list ([l (in-list (list 'arg.label ...))] 49 | [n (in-list (list 'arg.name ...))] 50 | [t (in-list (list arg.type ...))]) 51 | (rpc-arg l n (->field-type 'Backend t)))) 52 | (define info 53 | (rpc-info #f 'name args response-type name)) 54 | (sequencer-add! rpc-info-sequencer info) 55 | #,(when (eq? (syntax-local-context) 'module) 56 | #'(module+ rpc (provide name))))])) 57 | -------------------------------------------------------------------------------- /Racket/noise-serde-lib/private/callout.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require (for-syntax racket/base 4 | syntax/parse/pre 5 | "common.rkt") 6 | ffi/unsafe 7 | racket/port 8 | "../unsafe/callout.rkt" 9 | "sequencer.rkt" 10 | "serde.rkt") 11 | 12 | (provide 13 | define-callout 14 | 15 | callout-infos 16 | (struct-out callout-arg) 17 | (struct-out callout-info)) 18 | 19 | (struct callout-arg (name type)) 20 | (struct callout-info ([id #:mutable] name args cbox)) 21 | 22 | (define callout-infos (make-hasheqv)) 23 | (define callout-info-sequencer 24 | (make-sequencer 25 | callout-infos 26 | callout-info-name 27 | set-callout-info-id!)) 28 | 29 | (define-syntax (define-callout stx) 30 | (syntax-parse stx 31 | #:literals (:) 32 | [(_ (name:id [arg-name:id : arg-type:expr] ...+)) 33 | #:fail-unless (valid-name-stx? #'name) 34 | "callout names may only contain alphanumeric characters, dashes and underscores" 35 | #'(begin 36 | (define (name arg-name ...) 37 | (do-callout info (list (cons (->field-type 'Callout arg-type) arg-name) ...))) 38 | (define args 39 | (for/list ([n (in-list (list 'arg-name ...))] 40 | [t (in-list (list arg-type ...))]) 41 | (callout-arg n (->field-type 'Callout t)))) 42 | (define cbox 43 | (make-callout-box callout-type)) 44 | (define info 45 | (callout-info #f 'name args cbox)) 46 | (sequencer-add! callout-info-sequencer info))])) 47 | 48 | (define callout-type 49 | (_fun _int _size _bytes -> _void)) 50 | 51 | (define (do-callout info arg-pairs) 52 | (define id (callout-info-id info)) 53 | (define cbox (callout-info-cbox info)) 54 | (define bs 55 | (call-with-output-bytes 56 | (lambda (out) 57 | (for ([p (in-list arg-pairs)]) 58 | (write-field (car p) (cdr p) out))))) 59 | (cbox id (bytes-length bs) bs)) 60 | -------------------------------------------------------------------------------- /Racket/noise-serde-lib/private/common.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (provide 4 | valid-name-stx?) 5 | 6 | (define (valid-name-stx? id-stx) 7 | (define id-str (symbol->string (syntax-e id-stx))) 8 | (regexp-match? #rx"^[_a-zA-Z][_a-zA-Z0-9-]*$" id-str)) 9 | -------------------------------------------------------------------------------- /Racket/noise-serde-lib/private/debug.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require racket/string) 4 | 5 | (provide 6 | log-noise-debug 7 | log-noise-warning 8 | make-debug-input-port 9 | make-debug-output-port) 10 | 11 | (define-logger noise) 12 | 13 | (define debug-ports? 14 | (getenv "NOISE_DEBUG_PORTS")) 15 | 16 | (define (make-debug-input-port in) 17 | (if debug-ports? (do-make-debug-input-port in) in)) 18 | 19 | (define (make-debug-output-port out) 20 | (if debug-ports? (do-make-debug-output-port out) out)) 21 | 22 | (define (do-make-debug-input-port in) 23 | (make-input-port 24 | (object-name in) 25 | (lambda (out-bs) 26 | (define num-read 27 | (read-bytes-avail!* out-bs in)) 28 | (begin0 (if (zero? num-read) in num-read) 29 | (if (eof-object? num-read) 30 | (log-noise-debug "read: eof") 31 | (log-noise-debug "read: ~a" (~hex-bytes (subbytes out-bs 0 num-read)))))) 32 | (lambda (out-bs skip-n maybe-progress-evt) 33 | (define num-peeked 34 | (peek-bytes-avail!* out-bs skip-n maybe-progress-evt in)) 35 | (begin0 (if (zero? num-peeked) in num-peeked) 36 | (if (eof-object? num-peeked) 37 | (log-noise-debug "peek: eof") 38 | (log-noise-debug "peek: ~a" (~hex-bytes (subbytes out-bs 0 num-peeked)))))) 39 | (lambda () 40 | (close-input-port in)))) 41 | 42 | (define (do-make-debug-output-port out) 43 | (make-output-port 44 | (object-name out) 45 | out 46 | (lambda (bs start-pos end-pos _block? enable-break?) 47 | (define num-written 48 | (if enable-break? 49 | (parameterize-break #t 50 | (write-bytes-avail* bs out start-pos end-pos)) 51 | (write-bytes-avail* bs out start-pos end-pos))) 52 | (begin0 num-written 53 | (log-noise-debug "write: ~a" (~hex-bytes (subbytes bs start-pos (+ start-pos num-written)))))) 54 | (lambda () 55 | (close-output-port out)))) 56 | 57 | (define (~hex-bytes bs) 58 | (string-join 59 | (for/list ([b (in-bytes bs)]) 60 | (define hex 61 | (number->string b 16)) 62 | (if (< b 16) 63 | (format "0~a" hex) 64 | hex)) 65 | " ")) 66 | -------------------------------------------------------------------------------- /Racket/noise-serde-lib/private/sequencer.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require racket/match) 4 | 5 | (provide 6 | make-sequencer 7 | sequencer-add!) 8 | 9 | (struct sequencer (ht name-proc [names #:mutable] update!-proc)) 10 | 11 | (define (make-sequencer ht name-proc update!-proc) 12 | (sequencer ht name-proc null update!-proc)) 13 | 14 | (define (sequencer-add! s v) 15 | (match-define (sequencer ht name-proc names update!-proc) s) 16 | (define name (name-proc v)) 17 | (unless (symbol? name) 18 | (raise-argument-error 'sequencer-next! "(symbol? (name-proc v))" v)) 19 | (when (memq name names) 20 | (error 'sequencer-next! "duplicate name ~s" name)) 21 | (define new-names 22 | (sort (cons name names) symbolkeyword stx) 72 | (datum->syntax stx (string->keyword (symbol->string (syntax-e stx))))) 73 | (define (stx->bool-stx stx) 74 | (datum->syntax stx (and (syntax-e stx) #t))) 75 | 76 | (define-syntax-class record-field 77 | #:literals (:) 78 | (pattern [id:id : ft:expr {~alt {~optional {~and #:mutable mutable}} 79 | {~optional {~seq #:contract ctc-expr:expr}}} ...] 80 | #:with kwd (id-stx->keyword #'id) 81 | #:with arg #'id 82 | #:with ctc #'{~? ctc-expr any/c} 83 | #:with opt? #'#f 84 | #:with mut? (stx->bool-stx #'{~? mutable #f})) 85 | (pattern [(id:id def:expr) : ft:expr {~alt {~optional {~and #:mutable mutable}} 86 | {~optional {~seq #:contract ctc-expr:expr}}} ...] 87 | #:with kwd (id-stx->keyword #'id) 88 | #:with arg #'[id def] 89 | #:with ctc #'{~? ctc-expr any/c} 90 | #:with opt? #'#t 91 | #:with mut? (stx->bool-stx #'{~? mutable #f}))) 92 | 93 | (syntax-parse stx 94 | #:literals (:) 95 | [(_ {~or name:id (name:id : proto:protocol ...+)} 96 | fld:record-field ...) 97 | #:with name? (format-id #'name "~a?" #'name) 98 | #:with constructor-id (format-id #'name "make-~a" #'name) 99 | #:with (fld-accessor-id ...) 100 | (for/list ([arg (in-list (syntax-e #'(fld.id ...)))]) 101 | (format-id #'name "~a-~a" #'name arg)) 102 | #:with (fld-setter-id ...) 103 | (for/list ([arg (in-list (syntax-e #'(fld.id ...)))]) 104 | (format-id #'name "set-~a-~a" #'name arg)) 105 | #:with (constructor-arg ...) 106 | (apply 107 | append 108 | (for/list ([kwd (in-list (syntax-e #'(fld.kwd ...)))] 109 | [arg (in-list (syntax-e #'(fld.arg ...)))]) 110 | (list kwd arg))) 111 | #:with (required-ctor-arg-ctc ...) 112 | (apply 113 | append 114 | (for/list ([opt? (in-list (syntax->datum #'(fld.opt? ...)))] 115 | [kwd (in-list (syntax-e #'(fld.kwd ...)))] 116 | [ctc (in-list (syntax-e #'(fld.ctc ...)))] 117 | #:unless opt?) 118 | (list kwd ctc))) 119 | #:with (optional-ctor-arg-ctc ...) 120 | (apply 121 | append 122 | (for/list ([opt? (in-list (syntax->datum #'(fld.opt? ...)))] 123 | [kwd (in-list (syntax-e #'(fld.kwd ...)))] 124 | [ctc (in-list (syntax-e #'(fld.ctc ...)))] 125 | #:when opt?) 126 | (list kwd ctc))) 127 | #'(begin 128 | (define-syntax (name stx-or-mode) 129 | (case stx-or-mode 130 | [(provide-record) 131 | #'(combine-out name name? constructor-id fld-accessor-id ... fld-setter-id ...)] 132 | [else 133 | (unless (syntax? stx-or-mode) 134 | (raise-syntax-error 'name "unexpected argument to transformer" stx-or-mode)) 135 | (syntax-case stx-or-mode () 136 | [(_ arg (... ...)) #'(-name arg (... ...))] 137 | [id (identifier? #'id) #'info])])) 138 | (define-values (-name name? fld-accessor-id ... fld-setter-id ...) 139 | (let () 140 | (struct name (fld.id ...) 141 | #:transparent) 142 | (define/contract (fld-setter-id r v) 143 | (-> name? fld.ctc name?) 144 | (struct-copy name r [fld.id v])) ... 145 | (values name name? fld-accessor-id ... fld-setter-id ...))) 146 | (define info 147 | (let ([protocols {~? (list proto.e ...) null}] 148 | [fields (list (record-field 'fld.id (->field-type 'Record fld.ft) fld.mut? fld-accessor-id) ...)]) 149 | (record-info #f 'name -name protocols fields))) 150 | (sequencer-add! record-info-sequencer info) 151 | (define/contract (constructor-id constructor-arg ...) 152 | (->* (required-ctor-arg-ctc ...) 153 | (optional-ctor-arg-ctc ...) 154 | name?) 155 | (-name fld.id ...)))])) 156 | 157 | (define-syntax record-out 158 | (make-provide-transformer 159 | (lambda (stx modes) 160 | (syntax-parse stx 161 | [(_ id:id) 162 | (define export-stx 163 | ((syntax-local-value #'id) 'provide-record)) 164 | (expand-export export-stx modes)])))) 165 | 166 | (module+ test 167 | (require racket/port 168 | rackunit) 169 | 170 | (test-case "record serde" 171 | (define-record Human 172 | [name : String #:contract string?] 173 | [age : Varint #:contract (integer-in 0 100)]) 174 | (define h (make-Human #:name "Bogdan" #:age 30)) 175 | (define bs (with-output-to-bytes (λ () (write-record Human h)))) 176 | (check-equal? h (read-record Human (open-input-bytes bs))))) 177 | 178 | 179 | ;; enum ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 180 | 181 | (provide 182 | define-enum 183 | enum-out) 184 | 185 | (define-generics enum-variant-writer 186 | {write-enum-variant enum-variant-writer [out]}) 187 | 188 | (define (read-enum-variant info [in current-input-port]) 189 | (define variants (enum-info-variants info)) 190 | (define variant-idx (read-field UVarint in)) 191 | (unless (>= (vector-length variants) variant-idx) 192 | (error 'read-enum-variant "unknown variant index ~a for enum ~a" variant-idx (enum-info-name info))) 193 | (define variant (vector-ref variants variant-idx)) 194 | (apply 195 | (enum-variant-constructor variant) 196 | (for/list ([f (in-list (enum-variant-fields variant))]) 197 | (read-field (enum-variant-field-type f) in)))) 198 | 199 | (define (do-write-enum-variant info idx v [out (current-output-port)]) 200 | (define variant (vector-ref (enum-info-variants info) idx)) 201 | (write-field UVarint (enum-variant-id variant) out) 202 | (define last-field-name #f) 203 | (with-handlers ([exn:fail? 204 | (lambda (e) 205 | (define message 206 | (format "~a~n while writing enum variant field: ~a.~a.~a" 207 | (exn-message e) 208 | (enum-info-name info) 209 | (enum-variant-name variant) 210 | last-field-name)) 211 | (raise (exn:fail message (current-continuation-marks))))]) 212 | (for ([f (in-list (enum-variant-fields variant))]) 213 | (define type (enum-variant-field-type f)) 214 | (define value ((enum-variant-field-accessor f) v)) 215 | (set! last-field-name (enum-variant-field-name f)) 216 | (write-field type value out)))) 217 | 218 | (provide 219 | enum-infos 220 | (struct-out enum-info) 221 | (struct-out enum-variant) 222 | (struct-out enum-variant-field)) 223 | 224 | (struct enum-variant-field (name type accessor)) 225 | (struct enum-variant (id name constructor fields)) 226 | (struct enum-info ([id #:mutable] name protocols variants)) 227 | 228 | (define enum-infos (make-hasheqv)) 229 | (define enum-info-sequencer 230 | (make-sequencer 231 | enum-infos 232 | enum-info-name 233 | set-enum-info-id!)) 234 | 235 | (define-syntax (define-enum stx) 236 | (define-syntax-class enum-variant 237 | #:literals (:) 238 | (pattern [name:id {fld-name:id : fld-type:expr} ...])) 239 | 240 | (syntax-parse stx 241 | #:literals (:) 242 | [(_ {~or name:id (name:id : proto:protocol ...+)} variant:enum-variant ...+) 243 | #:with name? (format-id #'name "~a?" #'name) 244 | #:with (variant.idx ...) 245 | (for/list ([stx (in-list (syntax-e #'(variant ...)))] 246 | [idx (in-naturals)]) 247 | (datum->syntax stx idx)) 248 | #:with (variant.qualname ...) 249 | (for/list ([stx (in-list (syntax-e #'(variant.name ...)))]) 250 | (format-id #'name "~a.~a" #'name stx)) 251 | #:with (variant.qualname? ...) 252 | (for/list ([stx (in-list (syntax-e #'(variant.qualname ...)))]) 253 | (format-id stx "~a?" stx)) 254 | #:with ((variant.fld-accessor-id ...) ...) 255 | (for/list ([qual-stx (in-list (syntax-e #'(variant.qualname ...)))] 256 | [names-stx (in-list (syntax-e #'((variant.fld-name ...) ...)))]) 257 | (for/list ([stx (in-list (syntax-e names-stx))]) 258 | (format-id qual-stx "~a-~a" qual-stx stx))) 259 | #'(begin 260 | (define-syntax (name stx-or-mode) 261 | (case stx-or-mode 262 | [(provide-enum) 263 | #'(combine-out name name? 264 | variant.qualname ... 265 | variant.qualname? ... 266 | variant.fld-accessor-id ... ...)] 267 | [else 268 | (unless (syntax? stx-or-mode) 269 | (raise-syntax-error 'name "unexpected argument to transformer" stx-or-mode)) 270 | (syntax-case stx-or-mode () 271 | [id (identifier? #'id) #'info])])) 272 | (struct root () 273 | #:transparent 274 | #:reflection-name 'name) 275 | (define name? root?) 276 | (struct variant.qualname root (variant.fld-name ...) 277 | #:transparent 278 | #:methods gen:enum-variant-writer 279 | {(define (write-enum-variant self [out (current-output-port)]) 280 | (do-write-enum-variant info variant.idx self out))}) ... 281 | (define protocols 282 | {~? (list proto.e ...) null}) 283 | (define variants 284 | (vector 285 | (enum-variant 286 | variant.idx 287 | 'variant.name 288 | variant.qualname 289 | (list 290 | (enum-variant-field 291 | 'variant.fld-name 292 | (->field-type 'Enum variant.fld-type) 293 | variant.fld-accessor-id) ...)) ...)) 294 | (define info 295 | (enum-info #f 'name protocols variants)) 296 | (sequencer-add! enum-info-sequencer info))])) 297 | 298 | (define-syntax enum-out 299 | (make-provide-transformer 300 | (lambda (stx modes) 301 | (syntax-parse stx 302 | [(_ id:id) 303 | (define export-stx 304 | ((syntax-local-value #'id) 'provide-enum)) 305 | (expand-export export-stx modes)])))) 306 | 307 | (module+ test 308 | (test-case "enum serde" 309 | (define-enum Column 310 | [null] 311 | [default] 312 | [text {t : String}]) 313 | 314 | (define tests 315 | (list (Column.null) 316 | (Column.default) 317 | (Column.text "hello"))) 318 | (for ([t (in-list tests)]) 319 | (define bs (with-output-to-bytes (λ () (write-enum-variant t)))) 320 | (check-equal? t (read-enum-variant Column (open-input-bytes bs)))))) 321 | 322 | 323 | ;; varint ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 324 | 325 | (provide 326 | read-uvarint 327 | write-uvarint) 328 | 329 | (define-inline (write-uvarint* v out) 330 | ;; PERF: It is faster to batch up the bytes and issue a single 331 | ;; write to the output port than it is to make many individual 332 | ;; writes. 333 | (define bs 334 | (let loop ([bs null] [n v]) 335 | (define-values (q r) 336 | (quotient/remainder n #x80)) 337 | (if (zero? q) 338 | (apply bytes (reverse (cons r bs))) 339 | (loop (cons (bitwise-ior r #x80) bs) q)))) 340 | (write-bytes bs out)) 341 | 342 | (define (write-uvarint v [out (current-output-port)]) 343 | (if (< v #x80) 344 | (write-byte v out) 345 | (write-uvarint* v out))) 346 | 347 | (define (read-uvarint [in (current-input-port)]) 348 | (let loop ([s 0]) 349 | (define b (read-byte in)) 350 | (if (zero? (bitwise-and b #x80)) 351 | (arithmetic-shift b s) 352 | (+ (arithmetic-shift (bitwise-and b #x7F) s) 353 | (loop (+ s 7)))))) 354 | 355 | (define (write-varint v [out (current-output-port)]) 356 | (write-uvarint 357 | (bitwise-xor 358 | (arithmetic-shift v 1) 359 | (if (< v 0) -1 0)) 360 | out)) 361 | 362 | (define (read-varint [in (current-input-port)]) 363 | (define n (read-uvarint in)) 364 | (if (zero? (bitwise-and n 1)) 365 | (arithmetic-shift n -1) 366 | (bitwise-not (arithmetic-shift n -1)))) 367 | 368 | 369 | ;; field ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 370 | 371 | (provide 372 | HashTable 373 | Listof 374 | Optional 375 | Record 376 | Enum 377 | Delay 378 | StringConvertible 379 | 380 | (struct-out field-type) 381 | read-field 382 | write-field) 383 | 384 | (struct field-type 385 | (read-proc write-proc swift-proc)) 386 | 387 | (define (read-field t [in (current-input-port)]) 388 | ((field-type-read-proc t) in)) 389 | 390 | (define (write-field t v [out (current-output-port)]) 391 | ((field-type-write-proc t) v out)) 392 | 393 | (define-syntax (define-field-type stx) 394 | (syntax-parse stx 395 | [(_ id:id 396 | {~alt 397 | {~optional {~seq #:read read-expr:expr}} 398 | {~optional {~seq #:write write-expr:expr}} 399 | {~optional {~seq #:swift swift-expr:expr}}} ...) 400 | #'(begin 401 | (define id (field-type read-expr write-expr (~? swift-expr (λ () (symbol->string 'id))))) 402 | (provide id))])) 403 | 404 | (define-field-type Bool 405 | #:read (λ (in) 406 | (= (read-byte in) 1)) 407 | #:write (λ (b out) 408 | (write-byte (if b 1 0) out))) 409 | 410 | (define-field-type Bytes 411 | #:read (λ (in) 412 | (read-bytes (read-varint in) in)) 413 | #:write (λ (bs out) 414 | (write-varint (bytes-length bs) out) 415 | (write-bytes bs out)) 416 | #:swift (λ () "Data")) 417 | 418 | (define-syntax (define-float-field-type stx) 419 | (syntax-parse stx 420 | [(_ id:id size:number) 421 | #'(define-field-type id 422 | #:read (λ (in) (floating-point-bytes->real (read-bytes size in) #t)) 423 | #:write (λ (n out) (write-bytes (real->floating-point-bytes n size #t) out)))])) 424 | 425 | (define-float-field-type Float32 4) 426 | (define-float-field-type Float64 8) 427 | 428 | (define-syntax (define-integer-field-type stx) 429 | (syntax-parse stx 430 | [(_ id:id size:number) 431 | #'(define-integer-field-type id size #f)] 432 | [(_ id:id size:number #:signed) 433 | #'(define-integer-field-type id size #t)] 434 | [(_ id:id size:number signed?:expr) 435 | #'(define-field-type id 436 | #:read (λ (in) (integer-bytes->integer (read-bytes size in) signed? #t)) 437 | #:write (λ (n out) (write-bytes (integer->integer-bytes n size signed? #t) out)))])) 438 | 439 | (define-integer-field-type Int16 2 #:signed) 440 | (define-integer-field-type Int32 4 #:signed) 441 | (define-integer-field-type UInt16 2) 442 | (define-integer-field-type UInt32 4) 443 | 444 | (define-field-type String 445 | #:read (λ (in) 446 | (bytes->string/utf-8 (read-bytes (read-varint in) in))) 447 | #:write (λ (s out) 448 | (define bs (string->bytes/utf-8 s)) 449 | (write-varint (bytes-length bs) out) 450 | (write-bytes bs out))) 451 | 452 | (define-field-type Symbol 453 | #:read (λ (in) 454 | (define len (read-varint in)) 455 | (string->symbol (bytes->string/utf-8 (read-bytes len in)))) 456 | #:write (λ (s out) 457 | (define bs (string->bytes/utf-8 (symbol->string s))) 458 | (write-varint (bytes-length bs) out) 459 | (write-bytes bs out))) 460 | 461 | (define-field-type Varint 462 | #:read read-varint 463 | #:write write-varint) 464 | 465 | (define-field-type UVarint 466 | #:read read-uvarint 467 | #:write write-uvarint) 468 | 469 | (define-field-type Void 470 | #:read (λ (_in) (error 'Void "cannot read Void values")) 471 | #:write (λ (_v _out) (error 'Void "cannot write Void values")) 472 | #:swift (λ () "Void")) 473 | 474 | (provide 475 | ->field-type) 476 | 477 | (define (->field-type who t) 478 | (cond 479 | [(record-info? t) 480 | (Record t)] 481 | [(enum-info? t) 482 | (Enum t)] 483 | [else 484 | (begin0 t 485 | (unless (field-type? t) 486 | (raise-argument-error who "(or/c field-type? record-info?)" t)))])) 487 | 488 | (define (HashTable k v) 489 | (let ([k (->field-type 'HashTable k)] 490 | [v (->field-type 'HashTable v)]) 491 | (define k-read-proc (field-type-read-proc k)) 492 | (define v-read-proc (field-type-read-proc v)) 493 | (define k-write-proc (field-type-write-proc k)) 494 | (define v-write-proc (field-type-write-proc v)) 495 | (define k-swift-type ((field-type-swift-proc k))) 496 | (define v-swift-type ((field-type-swift-proc v))) 497 | (field-type 498 | (λ (in) 499 | (for/hash ([_ (in-range (read-varint in))]) 500 | (values 501 | (k-read-proc in) 502 | (v-read-proc in)))) 503 | (λ (h out) 504 | (write-varint (hash-count h) out) 505 | (for ([(k v) (in-hash h)]) 506 | (k-write-proc k out) 507 | (v-write-proc v out))) 508 | (λ () 509 | (format "[~a: ~a]" 510 | k-swift-type 511 | v-swift-type))))) 512 | 513 | (define (Listof t) 514 | (let ([t (->field-type 'Listof t)]) 515 | (define read-proc (field-type-read-proc t)) 516 | (define write-proc (field-type-write-proc t)) 517 | (define swift-type ((field-type-swift-proc t))) 518 | (field-type 519 | (λ (in) 520 | (for/list ([_ (in-range (read-varint in))]) 521 | (read-proc in))) 522 | (λ (vs out) 523 | (write-varint (length vs) out) 524 | (for-each (λ (v) (write-proc v out)) vs)) 525 | (λ () 526 | (format "[~a]" swift-type))))) 527 | 528 | (define (Optional t) 529 | (let ([t (->field-type 'Optional t)]) 530 | (define read-proc (field-type-read-proc t)) 531 | (define write-proc (field-type-write-proc t)) 532 | (define swift-type ((field-type-swift-proc t))) 533 | (field-type 534 | (λ (in) 535 | (and (not (zero? (read-byte in))) 536 | (read-proc in))) 537 | (λ (v out) 538 | (cond 539 | [v 540 | (write-byte 1 out) 541 | (write-proc v out)] 542 | [else 543 | (write-byte 0 out)])) 544 | (λ () 545 | (format "~a?" swift-type))))) 546 | 547 | (define (Record t) 548 | (unless (record-info? t) 549 | (raise-argument-error 'Record "record-info?" t)) 550 | (field-type 551 | (λ (in) (read-record t in)) 552 | (λ (v out) (write-record t v out)) 553 | (λ () (symbol->string (record-info-name t))))) 554 | 555 | (define (Enum t) 556 | (unless (enum-info? t) 557 | (raise-argument-error 'Enum "enum-info?" t)) 558 | (field-type 559 | (λ (in) (read-enum-variant t in)) 560 | (λ (v out) (write-enum-variant v out)) 561 | (λ () (symbol->string (enum-info-name t))))) 562 | 563 | (define (Delay* t-proc) 564 | (define (force) 565 | (->field-type 'Delay (t-proc))) 566 | (field-type 567 | (λ (in) ((field-type-read-proc (force)) in)) 568 | (λ (v out) ((field-type-write-proc (force)) v out)) 569 | (λ () ((field-type-swift-proc (force)))))) 570 | 571 | (define-syntax-rule (Delay e) 572 | (Delay* (λ () e))) 573 | 574 | (define (StringConvertible string-> ->string) 575 | (field-type 576 | (λ (in) (string-> ((field-type-read-proc String) in))) 577 | (λ (v out) ((field-type-write-proc String) (->string v) out)) 578 | (λ () ((field-type-swift-proc String))))) 579 | 580 | (module+ test 581 | (require racket/string) 582 | 583 | (test-case "complex field serde" 584 | (define-record Example 585 | [b : Bool #:contract boolean?] 586 | [i : Varint #:contract integer?] 587 | [s : String #:contract string?] 588 | [l : (Listof Varint) #:contract list?]) 589 | (define v (Example #t -1 "hello" '(0 1 2 #x-FF #x7F #xFFFF))) 590 | (define bs (with-output-to-bytes (λ () (write-record Example v)))) 591 | (check-equal? v (read-record Example (open-input-bytes bs)))) 592 | 593 | (test-case "container serde" 594 | (define-record Story 595 | [id : UVarint #:contract exact-integer?] 596 | [title : String #:contract string?] 597 | [comments : (Listof UVarint) #:contract (listof exact-integer?)] 598 | [metadata : (HashTable Symbol String) #:contract (hash/c symbol? string?)]) 599 | (define-record Stories 600 | [stories : (Listof Story) #:contract (listof Story?)]) 601 | (define v 602 | (Stories 603 | (list (Story 0 "a" null (hash 'a "a" 'b "b")) 604 | (Story 1 "b" '(1 2 3) (hash 'c "def"))))) 605 | (define bs (with-output-to-bytes (λ () (write-record Stories v)))) 606 | (check-equal? v (read-record Stories (open-input-bytes bs)))) 607 | 608 | (test-case "nested record serde" 609 | (define-record A 610 | [s : String]) 611 | (define-record B 612 | [a : A]) 613 | (define v 614 | (B (A "test"))) 615 | (define bs (with-output-to-bytes (λ () (write-record B v)))) 616 | (check-equal? v (read-record B (open-input-bytes bs)))) 617 | 618 | (test-case "record with enum serde" 619 | (define-enum Result 620 | [err {message : String}] 621 | [ok {value : UVarint}]) 622 | (define-record C 623 | [res : Result]) 624 | (define v 625 | (C (Result.err "an error"))) 626 | (define bs (with-output-to-bytes (λ () (write-record C v)))) 627 | (check-equal? v (read-record C (open-input-bytes bs)))) 628 | 629 | (test-case "mutually-recursive types" 630 | (define-enum ApplyResult 631 | [stack {s : (Delay Stack)}] 632 | [text {t : String}]) 633 | (define-record Stack 634 | [direction : Symbol] 635 | [children : (Listof ApplyResult)]) 636 | (define v 637 | (ApplyResult.stack 638 | (make-Stack 639 | #:direction 'horizontal 640 | #:children (list 641 | (ApplyResult.text "Hello") 642 | (ApplyResult.stack 643 | (make-Stack 644 | #:direction 'vertical 645 | #:children (list (ApplyResult.text "a") 646 | (ApplyResult.text "b")))))))) 647 | (define bs (with-output-to-bytes (λ () (write-field (Enum ApplyResult) v)))) 648 | (check-equal? v (read-field (Enum ApplyResult) (open-input-bytes bs))) 649 | (check-exn 650 | (regexp 651 | (regexp-quote 652 | (string-join 653 | '("string->bytes/utf-8: contract violation" 654 | " expected: string?" 655 | " given: #f" 656 | " while writing enum variant field: ApplyResult.text.t" 657 | " while writing record field: Stack.children") 658 | "\n"))) 659 | (lambda () 660 | (write-record 661 | Stack 662 | (Stack 663 | 'horizontal 664 | (list 665 | (ApplyResult.text #f))) 666 | (open-output-nowhere))))) 667 | 668 | (test-case "enum with protocols" 669 | (define-enum (Foo : Equatable) 670 | [foo] 671 | [bar]) 672 | (check-equal? 673 | (enum-info-protocols Foo) 674 | '(Equatable))) 675 | 676 | (test-case "record with protocols" 677 | (define-record (Foo : Equatable Identifiable) 678 | [id : UVarint]) 679 | (check-equal? 680 | (record-info-protocols Foo) 681 | '(Equatable Identifiable)))) 682 | -------------------------------------------------------------------------------- /Racket/noise-serde-lib/serde.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require "private/serde.rkt") 4 | (provide 5 | define-record : 6 | record-out 7 | record-info? 8 | 9 | define-enum 10 | enum-out 11 | enum-info? 12 | 13 | field-type? 14 | Bool 15 | Bytes 16 | Delay 17 | Float32 18 | Float64 19 | Int16 20 | Int32 21 | Varint 22 | UInt16 23 | UInt32 24 | UVarint 25 | HashTable 26 | Listof 27 | Optional 28 | String 29 | StringConvertible 30 | Symbol) 31 | -------------------------------------------------------------------------------- /Racket/noise-serde-lib/unsafe/callout.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require ffi/unsafe) 4 | 5 | (provide 6 | callout-box? 7 | make-callout-box 8 | callout-box-install!) 9 | 10 | (struct callout-box (type [proc #:mutable]) 11 | #:property prop:procedure (λ (b . args) 12 | (define proc (callout-box-proc b)) 13 | (unless proc 14 | (error 'callout-box "procedure not installed")) 15 | (apply (callout-box-proc b) args))) 16 | 17 | (define (make-callout-box type) 18 | (callout-box type #f)) 19 | 20 | (define (callout-box-install! b addr) 21 | (set-callout-box-proc! b (cast addr _intptr (callout-box-type b)))) 22 | -------------------------------------------------------------------------------- /Racket/noise-serde-lint-lib/examples/basic.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require noise/backend 4 | noise/serde) 5 | 6 | (define-rpc (echo [s : String] : String) 7 | (void)) 8 | -------------------------------------------------------------------------------- /Racket/noise-serde-lint-lib/examples/info.rkt: -------------------------------------------------------------------------------- 1 | #lang info 2 | 3 | (define compile-omit-paths 'all) 4 | (define test-omit-paths 'all) 5 | -------------------------------------------------------------------------------- /Racket/noise-serde-lint-lib/info.rkt: -------------------------------------------------------------------------------- 1 | #lang info 2 | 3 | (define license 'BSD-3-Clause) 4 | (define collection "noise") 5 | (define deps 6 | '("base" 7 | "review")) 8 | (define review-exts 9 | '([noise/review should-review-syntax? review-syntax])) 10 | -------------------------------------------------------------------------------- /Racket/noise-serde-lint-lib/review.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | #|review: ignore|# 4 | 5 | (require review/ext 6 | syntax/parse/pre) 7 | 8 | (provide 9 | should-review-syntax? 10 | review-syntax) 11 | 12 | (define (should-review-syntax? stx) 13 | (syntax-case stx (define-enum define-record define-rpc) 14 | [(define-enum . _rest) #t] 15 | [(define-record . _rest) #t] 16 | [(define-rpc . _rest) #t] 17 | [_ #f])) 18 | 19 | (define-syntax-class enum-definition 20 | #:datum-literals (define-enum :) 21 | (pattern (define-enum 22 | ~! 23 | {~or enum-id:id (enum-id:id : protocol-id:id ...+)} 24 | [variant-id:id {field-id:id : field-type:expression} ...] ...) 25 | #:do [(track-binding #'enum-id #:check-usages? #f) 26 | (track-binding #'enum-id "~a?" #:check-usages? #f) 27 | (define enum-id-sym (syntax->datum #'enum-id)) 28 | (for ([variant-id-stx (in-list (syntax-e #'(variant-id ...)))]) 29 | (track-binding 30 | variant-id-stx 31 | #:related-to #'enum-id 32 | #:check-usages? #f 33 | (format "~a.~~a" enum-id-sym)))])) 34 | 35 | (define-syntax-class record-field 36 | (pattern [id:id : type-expr:expression . opts]) 37 | (pattern [(id:id default-expr:expression) : type-expr:expression . opts])) 38 | 39 | (define-syntax-class record-definition 40 | #:datum-literals (define-record :) 41 | (pattern (define-record 42 | ~! 43 | {~or record-id:id (record-id:id : protocol-id:id ...+)} 44 | record-field:record-field ...+) 45 | #:do [(track-binding #'record-id #:check-usages? #f) 46 | (track-binding #'record-id "~a?" #:check-usages? #f) 47 | (track-binding #'record-id "make-~a" #:check-usages? #f) 48 | (define record-id-sym (syntax->datum #'record-id)) 49 | (for ([record-field-id-stx (in-list (syntax-e #'(record-field.id ...)))]) 50 | (for ([p (in-list '("" "set-"))]) 51 | (track-binding 52 | record-field-id-stx 53 | #:related-to #'record-id 54 | #:check-usages? #f 55 | (format "~a~a-~~a" p record-id-sym))))])) 56 | 57 | (define-syntax-class rpc-arg 58 | #:datum-literals (:) 59 | (pattern [{~optional _} id:id : type-expr:expression] 60 | #:do [(track-binding #'id)])) 61 | 62 | (define-syntax-class rpc-definition 63 | #:datum-literals (define-rpc :) 64 | (pattern (define-rpc 65 | ~! 66 | {~do (push-scope)} 67 | (name:id arg:rpc-arg ... {~optional {~seq : type-expr:expression}}) 68 | {~do (push-scope)} 69 | body-e:expression ...) 70 | #:do [(pop-scope) 71 | (pop-scope) 72 | (track-binding #'name #:check-usages? #f)])) 73 | 74 | (define (review-syntax stx) 75 | (syntax-parse stx 76 | [d:enum-definition #'d] 77 | [d:record-definition #'d] 78 | [d:rpc-definition #'d])) 79 | -------------------------------------------------------------------------------- /Sources/Noise/Racket.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import RacketCS 3 | 4 | #if arch(x86_64) 5 | let ARCH = "x86_64" 6 | #elseif arch(arm64) 7 | let ARCH = "arm64" 8 | #else 9 | #error("unsupported platform") 10 | #endif 11 | 12 | #if os(macOS) 13 | import NoiseBoot_macOS 14 | 15 | let OS = "macos" 16 | #elseif os(iOS) 17 | import NoiseBoot_iOS 18 | 19 | let OS = "ios" 20 | #else 21 | #error("unsupported OS") 22 | #endif 23 | 24 | /// The Racket runtime. 25 | /// 26 | /// # Threading 27 | /// 28 | /// The thread on which the runtime is instantiated is considered the 29 | /// main Racket place. All Racket operations must be run on that 30 | /// thread. You may work with Chez Scheme values and call Chez Scheme 31 | /// primitives from other threads (see `bracket` and `activate`). 32 | /// 33 | /// - Warning: Only one instance may be created per process. 34 | public struct Racket { 35 | public init(execPath: String = "racket") { 36 | var args = racket_boot_arguments_t() 37 | args.exec_file = execPath.utf8CString.cstring() 38 | args.boot1_path = NoiseBoot.petiteURL.path.utf8CString.cstring() 39 | args.boot2_path = NoiseBoot.schemeURL.path.utf8CString.cstring() 40 | args.boot3_path = NoiseBoot.racketURL.path.utf8CString.cstring() 41 | racket_boot(&args) 42 | racket_deactivate_thread() 43 | args.exec_file.deallocate() 44 | args.boot1_path.deallocate() 45 | args.boot2_path.deallocate() 46 | args.boot3_path.deallocate() 47 | } 48 | 49 | /// Loads compiled Racket code. 50 | /// 51 | /// - Warning: This function must be called from the same thread the 52 | /// Racket runtime was initialized on. 53 | public func load(zo: URL) { 54 | let path = zo.path.utf8CString.cstring() 55 | racket_embedded_load_file(path, 1) 56 | path.deallocate() 57 | } 58 | 59 | /// Requires `what` from the module at path `mod`. 60 | /// 61 | /// - Warning: This function must be called from the same thread the 62 | /// Racket runtime was initialized on. 63 | public func require(_ what: Val, from mod: Val) -> Val { 64 | return Val(ptr: racket_dynamic_require(mod.ptr, what.ptr)) 65 | } 66 | 67 | /// Calls `proc` after activating the current thread. Deactivates 68 | /// the thread before returning `proc`'s result. 69 | public func bracket(proc: () -> T) -> T { 70 | racket_activate_thread() 71 | let res = proc() 72 | racket_deactivate_thread() 73 | return res 74 | } 75 | 76 | /// Makes the current thread known to Chez Scheme. 77 | /// 78 | /// - Warning: Accessing Chez Scheme data from inactive threads 79 | /// races against the garbage collector. 80 | /// - Warning: Active threads that aren't running Scheme code block 81 | /// the garbage collector, so deactivate unused threads with 82 | /// `deactivate`. 83 | public func activate() { 84 | racket_activate_thread() 85 | } 86 | 87 | public func deactivate() { 88 | racket_deactivate_thread() 89 | } 90 | 91 | /// Tears down the Chez Scheme runtime. 92 | public func destroy() { 93 | racket_destroy() 94 | } 95 | } 96 | 97 | /// An unsafe wrapper for Chez Scheme values. 98 | /// 99 | /// - Note: On macOS x86_64 and aarch64, `ptr` values are real OS 100 | /// pointers represented as `void *`s. On iOS, we use the portable 101 | /// bytecode interpreter, so pointers are represented as `unsigned 102 | /// long long`s. For now, we handle the difference here using platform 103 | /// conditionals. If ever we're able to use native code on iOS, that'll 104 | /// have to change at least. 105 | /// 106 | /// - Warning: Values may be moved by the GC at any time, so these 107 | /// helpers should mainly be used to create data to be passed into 108 | /// Racket, and to copy data from Racket within activated threads. 109 | public struct Val { 110 | #if os(iOS) 111 | let ptr: ptr 112 | #else 113 | let ptr: ptr? 114 | #endif 115 | 116 | /// The empty list. 117 | nonisolated(unsafe) public static let null = Val(ptr: racket_nil()) 118 | 119 | /// The true value. 120 | nonisolated(unsafe) public static let f = Val(ptr: racket_false()) 121 | 122 | /// The false value. 123 | nonisolated(unsafe) public static let t = Val(ptr: racket_true()) 124 | 125 | /// Creates a Chez Scheme fixnum. 126 | public static func fixnum(_ i: Int) -> Val { 127 | #if os(iOS) 128 | return Val(ptr: racket_fixnum(Int64(i))) 129 | #else 130 | return Val(ptr: racket_fixnum(i)) 131 | #endif 132 | } 133 | 134 | /// Creates a Chez Scheme integer representing a pointer address. 135 | public static func pointer(_ p: UnsafeMutableRawPointer) -> Val { 136 | #if os(iOS) 137 | return Val(ptr: racket_pointer(UInt64(UInt(bitPattern: p)))) 138 | #else 139 | return Val(ptr: racket_pointer(p)) 140 | #endif 141 | } 142 | 143 | /// Creates a Chez Scheme symbol by copying a String. 144 | public static func symbol(_ s: String) -> Val { 145 | let c = s.utf8CString.cstring() 146 | let p = racket_symbol(c) 147 | c.deallocate() 148 | return Val(ptr: p) 149 | } 150 | 151 | /// Creates a Chez Scheme string by copying a regular String. 152 | public static func string(_ s: String) -> Val { 153 | let utf8 = s.utf8CString 154 | let c = utf8.cstring() 155 | #if os(iOS) 156 | let p = racket_string(c, UInt64(utf8.underestimatedCount - 1)) 157 | #else 158 | let p = racket_string(c, UInt(utf8.underestimatedCount - 1)) 159 | #endif 160 | c.deallocate() 161 | return Val(ptr: p) 162 | } 163 | 164 | /// Creates a pair of two Values. 165 | public static func cons(_ a: Val, _ b: Val) -> Val { 166 | return Val(ptr: racket_cons(a.ptr, b.ptr)) 167 | } 168 | 169 | /// Locks the value to prevent the GC from moving it. Panics if 170 | /// called with an immediate value. 171 | public func lock() { 172 | #if os(iOS) 173 | racket_lock_object(ptr) 174 | #else 175 | racket_lock_object(ptr!) 176 | #endif 177 | } 178 | 179 | /// Unlocks the value to let the GC move it. Panics if called with 180 | /// an immediate value. 181 | public func unlock() { 182 | #if os(iOS) 183 | racket_unlock_object(ptr) 184 | #else 185 | racket_unlock_object(ptr!) 186 | #endif 187 | } 188 | 189 | /// Like `lock`, but returns the value. 190 | public func locked() -> Val { 191 | lock() 192 | return self 193 | } 194 | 195 | /// Like `unlock`, but returns the value. 196 | public func unlocked() -> Val { 197 | unlock() 198 | return self 199 | } 200 | 201 | /// Applies the value using `args`. 202 | @discardableResult 203 | public func apply(_ args: Val) -> Val? { 204 | if racket_procedurep(ptr) == 1{ 205 | return unsafeApply(args) 206 | } 207 | return nil 208 | } 209 | 210 | /// Applies the value using `args`, panicking if the value is not a 211 | /// procedure. 212 | @discardableResult 213 | public func unsafeApply(_ args: Val) -> Val { 214 | return Val(ptr: racket_apply(ptr, args.ptr)) 215 | } 216 | 217 | // Returns the `car` of a pair. 218 | public func car() -> Val? { 219 | if racket_pairp(ptr) == 1 { 220 | return unsafeCar() 221 | } 222 | return nil 223 | } 224 | 225 | // Returns the `cdr` of a pair. 226 | public func cdr() -> Val? { 227 | if racket_pairp(ptr) == 1 { 228 | return unsafeCdr() 229 | } 230 | return nil 231 | } 232 | 233 | /// Returns the `car` of a pair, panicking if the value is not a 234 | /// pair. 235 | public func unsafeCar() -> Val { 236 | #if os(iOS) 237 | return Val(ptr: racket_car(ptr)) 238 | #else 239 | return Val(ptr: racket_car(ptr!)) 240 | #endif 241 | } 242 | 243 | /// Returns the `cdr` of a pair, panicking if the value is not a 244 | /// pair. 245 | public func unsafeCdr() -> Val { 246 | #if os(iOS) 247 | return Val(ptr: racket_cdr(ptr)) 248 | #else 249 | return Val(ptr: racket_cdr(ptr!)) 250 | #endif 251 | } 252 | 253 | /// Extracts the integer value of a fixnum. 254 | public func fixnum() -> Int? { 255 | if racket_fixnump(ptr) == 1 { 256 | return unsafeFixnum() 257 | } 258 | return nil 259 | } 260 | 261 | /// Extracts the integer value of a fixnum, panicking if the value 262 | /// is not a fixnum. 263 | public func unsafeFixnum() -> Int { 264 | #if os(iOS) 265 | return Int(racket_fixnum_value(ptr)) 266 | #else 267 | return racket_fixnum_value(ptr) 268 | #endif 269 | } 270 | 271 | /// Copies a Chez Scheme bytevector value into a String. 272 | public func bytestring() -> String? { 273 | if racket_bytevectorp(ptr) == 1 { 274 | return unsafeBytestring() 275 | } 276 | return nil 277 | } 278 | 279 | /// Copies a Chez Scheme bytevector value into a String, panicking 280 | /// if the value is not a bytevector. 281 | public func unsafeBytestring() -> String? { 282 | return unsafeBytevector(nulTerminated: true).withUnsafeBufferPointer { buf -> String? in 283 | return String(validatingCString: buf.baseAddress!) 284 | } 285 | } 286 | 287 | /// Copies a Chez Scheme bytevector into an `Array` of `CChar`s. 288 | /// 289 | /// - Warning: Chez Scheme `byte`s are unsigned, but they get 290 | /// converted to signed in Swift. 291 | public func bytevector(nulTerminated nul: Bool = false) -> [CChar]? { 292 | if racket_bytevectorp(ptr) == 1 { 293 | return unsafeBytevector(nulTerminated: nul) 294 | } 295 | return nil 296 | } 297 | 298 | /// Copies a Chez Scheme bytevector into a Swift array, panicking if 299 | /// the value is not a bytevector. 300 | /// 301 | /// When the `nulTerminated` argument is `true`, the bytevector will 302 | /// contain an extra 0 byte at the end. 303 | public func unsafeBytevector(nulTerminated: Bool = false) -> [CChar] { 304 | #if os(iOS) 305 | let len = Int(racket_bytevector_length(ptr)) 306 | let data = racket_bytevector_data(ptr) 307 | #else 308 | let len = Int(racket_bytevector_length(ptr!)) 309 | let data = racket_bytevector_data(ptr!) 310 | #endif 311 | var res = Array(repeating: 0, count: nulTerminated ? len+1 : len) 312 | res.withUnsafeMutableBytes { dst in 313 | dst.copyBytes(from: UnsafeRawBufferPointer(start: data, count: Int(len))) 314 | } 315 | return res 316 | } 317 | } 318 | 319 | fileprivate extension ContiguousArray where Element == CChar { 320 | func cstring() -> UnsafePointer { 321 | let p = UnsafeMutablePointer.allocate(capacity: self.underestimatedCount) 322 | self.withUnsafeBufferPointer { ptr in 323 | p.initialize(from: ptr.baseAddress!, count: self.underestimatedCount) 324 | } 325 | return UnsafePointer(p) 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /Sources/NoiseBackend/Backend.swift: -------------------------------------------------------------------------------- 1 | import Dispatch 2 | import Foundation 3 | import Noise 4 | import NoiseSerde 5 | import OSLog 6 | 7 | fileprivate let logger = Logger( 8 | subsystem: "io.defn.NoiseBackend", 9 | category: "Backend" 10 | ) 11 | 12 | /// Statistics reported by Backends. 13 | public struct BackendStats: Sendable { 14 | public let totalRequests: UInt64 15 | public let totalWaitNanos: UInt64 16 | public let totalReadNanos: UInt64 17 | public let totalWriteNanos: UInt64 18 | } 19 | 20 | /// Client implementation for an async Racket backend. 21 | public final class Backend: @unchecked Sendable { 22 | private let ip = Pipe() // in from Racket's perspective 23 | private let op = Pipe() // out from Racket's perspective 24 | 25 | private let mu = DispatchSemaphore(value: 1) // mu guards everything below here 26 | private let out: OutputPort! 27 | private var seq = UVarint(0) 28 | fileprivate var pending = [UInt64: ResponseHandler]() 29 | private var totalRequests = UInt64(0) 30 | private var totalWaitNanos = UInt64(0) 31 | private var totalReadNanos = UInt64(0) 32 | private var totalWriteNanos = UInt64(0) 33 | 34 | public init(withZo zo: URL, andMod modname: String, andProc proc: String) { 35 | out = FileHandleOutputPort(withHandle: ip.fileHandleForWriting) 36 | let server = Thread { 37 | self.serve(zo, modname, proc) 38 | } 39 | server.name = "Noise Backend (Server)" 40 | server.qualityOfService = .userInitiated 41 | server.start() 42 | let reader = Thread { 43 | self.read() 44 | } 45 | reader.name = "Noise Backend (Reader)" 46 | reader.qualityOfService = .userInitiated 47 | reader.start() 48 | } 49 | 50 | private func serve(_ zo: URL, _ modname: String, _ proc: String) { 51 | let r = Racket(execPath: zo.path) 52 | r.bracket { 53 | r.load(zo: zo) 54 | let mod = Val.cons(Val.symbol("quote"), Val.cons(Val.symbol(modname), Val.null)) 55 | let ifd = Val.fixnum(Int(ip.fileHandleForReading.fileDescriptor)) 56 | let ofd = Val.fixnum(Int(op.fileHandleForWriting.fileDescriptor)) 57 | let serve = r.require(Val.symbol(proc), from: mod).unsafeCar() 58 | serve.unsafeApply(Val.cons(ifd, Val.cons(ofd, Val.null))) 59 | preconditionFailure("Racket server exited") 60 | } 61 | } 62 | 63 | private func read() { 64 | let inp = FileHandleInputPort(withHandle: op.fileHandleForReading) 65 | var buf = Data(count: 8*1024) // will grow as needed 66 | while true { 67 | let id = UVarint.read(from: inp, using: &buf) 68 | //logger.debug("\(RequestId(value: id)): reading response; bufsize: \(buf.count)b") 69 | mu.wait() 70 | guard let handler = pending[id] else { 71 | logger.fault("\(RequestId(value: id)): future is gone") 72 | mu.signal() 73 | continue 74 | } 75 | mu.signal() 76 | let readDuration = handler.handle(from: inp, using: &buf) 77 | //logger.debug("\(RequestId(value: id)): took \(Duration(nanos: readDuration), privacy: .public) to read") 78 | mu.wait() 79 | pending.removeValue(forKey: id) 80 | let requestDuration = DispatchTime.now().uptimeNanoseconds - handler.time.uptimeNanoseconds 81 | totalRequests += 1 82 | totalWaitNanos += requestDuration 83 | totalReadNanos += readDuration 84 | mu.signal() 85 | logger.debug("\(RequestId(value: id)): took \(Duration(nanos: requestDuration), privacy: .public) to fulfill") 86 | } 87 | } 88 | 89 | public func send( 90 | writeProc write: (OutputPort) -> Void, 91 | readProc read: @escaping (InputPort, inout Data) -> T, 92 | commandName: String = #function 93 | ) -> Future { 94 | mu.wait() 95 | let id = seq 96 | seq += 1 97 | logger.debug("\(RequestId(value: id)): \(commandName)") 98 | let t0 = DispatchTime.now() 99 | id.write(to: out) 100 | write(out) 101 | out.flush() 102 | let dt = DispatchTime.now().uptimeNanoseconds - t0.uptimeNanoseconds 103 | let fut = Future() 104 | let handler = ResponseHandlerImpl(id: id, fut: fut, read: read) 105 | pending[id] = handler 106 | totalWriteNanos += dt 107 | mu.signal() 108 | return fut 109 | } 110 | 111 | public func stats() -> BackendStats { 112 | mu.wait() 113 | defer { mu.signal() } 114 | return BackendStats( 115 | totalRequests: totalRequests, 116 | totalWaitNanos: totalWaitNanos, 117 | totalReadNanos: totalReadNanos, 118 | totalWriteNanos: totalWriteNanos 119 | ) 120 | } 121 | } 122 | 123 | fileprivate struct Request: Writable { 124 | let id: UVarint 125 | let data: Data 126 | 127 | func write(to out: OutputPort) { 128 | id.write(to: out) 129 | data.write(to: out) 130 | } 131 | } 132 | 133 | fileprivate protocol ResponseHandler { 134 | var time: DispatchTime { get } 135 | 136 | func handle(from inp: InputPort, using buf: inout Data) -> UInt64 137 | } 138 | 139 | fileprivate struct ResponseHandlerImpl: ResponseHandler where T: Sendable { 140 | let id: UInt64 141 | let fut: Future 142 | let read: (InputPort, inout Data) -> T 143 | let time = DispatchTime.now() 144 | 145 | func handle(from inp: InputPort, using buf: inout Data) -> UInt64 { 146 | let t0 = DispatchTime.now() 147 | if inp.readByte() == 1 { 148 | fut.resolve(with: read(inp, &buf)) 149 | } else { 150 | fut.reject(with: String.read(from: inp, using: &buf)) 151 | } 152 | return DispatchTime.now().uptimeNanoseconds - t0.uptimeNanoseconds 153 | } 154 | } 155 | 156 | fileprivate struct RequestId: CustomStringConvertible { 157 | let value: UInt64 158 | 159 | var description: String { 160 | return String(format: "#%06d", value) 161 | } 162 | } 163 | 164 | fileprivate struct Duration: CustomStringConvertible { 165 | let nanos: UInt64 166 | 167 | var description: String { 168 | if nanos > 1_000_000_000 { 169 | return "\(nanos/1_000_000_000)s" 170 | } else if nanos > 1_000_000 { 171 | return "\(nanos/1_000_000)ms" 172 | } else if nanos > 1_000 { 173 | return "\(nanos/1_000)µs" 174 | } 175 | return "\(nanos)ns" 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /Sources/NoiseBackend/Callout.swift: -------------------------------------------------------------------------------- 1 | import Dispatch 2 | import Foundation 3 | import NoiseSerde 4 | 5 | public func installCallback( 6 | id: UInt64, 7 | rpc: (UVarint, Varint) -> Future, 8 | proc: @escaping (InputPort) -> Void 9 | ) -> Future { 10 | callbacksSema.wait() 11 | callbacks[id] = proc 12 | callbacksSema.signal() 13 | let addr = Int(bitPattern: unsafeBitCast(callbackHandler, to: Optional.self)!) 14 | return rpc(id, Int64(addr)) 15 | } 16 | 17 | nonisolated(unsafe) fileprivate var callbacks = [UInt64: (InputPort) -> Void]() 18 | nonisolated(unsafe) fileprivate var callbacksSema = DispatchSemaphore(value: 1) 19 | nonisolated(unsafe) fileprivate let callbackHandler: @convention(c) (UInt64, Int, UnsafePointer) -> Void = { id, len, ptr in 20 | let data = Data(bytes: ptr, count: len) 21 | let pipe = Pipe() 22 | DispatchQueue.global(qos: .background).async { 23 | try! pipe.fileHandleForWriting.write(contentsOf: data) 24 | try! pipe.fileHandleForWriting.close() 25 | } 26 | callbacksSema.wait() 27 | let proc = callbacks[id] 28 | callbacksSema.signal() 29 | proc!(FileHandleInputPort(withHandle: pipe.fileHandleForReading)) 30 | } 31 | -------------------------------------------------------------------------------- /Sources/NoiseBackend/Future.swift: -------------------------------------------------------------------------------- 1 | import Dispatch 2 | import Foundation 3 | 4 | nonisolated(unsafe) private var defaultErrorHandlerMu = DispatchSemaphore(value: 1) 5 | nonisolated(unsafe) private var defaultErrorHandler: (Any) -> Void = { err in 6 | preconditionFailure("unexpected error: \(err)") 7 | } 8 | 9 | /// A container for data that will be received from a Backend at some 10 | /// point. 11 | public final class Future: @unchecked Sendable where Err: Sendable, Res: Sendable { 12 | private let mu = DispatchSemaphore(value: 1) 13 | private var waiters = [DispatchSemaphore]() 14 | 15 | private enum State { 16 | case pending 17 | case canceled 18 | case error(Err) 19 | case ok(Res) 20 | } 21 | 22 | private var state = State.pending 23 | 24 | /// Thrown by `Future.wait` when a Future is canceled. 25 | public struct Canceled: Error {} 26 | 27 | /// Thrown by `Future.wait` on error. 28 | public struct WaitError: LocalizedError where E: Sendable { 29 | let error: E 30 | 31 | public var errorDescription: String? { 32 | if let err = error as? String { 33 | return err 34 | } 35 | return "\(error)" 36 | } 37 | } 38 | 39 | /// Represents the disjoint result values that may be returned by 40 | /// calls to `Future.wait(timeout:)`. 41 | public enum WaitResult: Sendable where E: Sendable, R: Sendable { 42 | case timedOut 43 | case canceled 44 | case error(E) 45 | case ok(R) 46 | } 47 | 48 | public init() {} 49 | 50 | /// Resolve the future with `d` and signal all the waiters (if any). 51 | public func resolve(with res: Res) { 52 | transition(toState: .ok(res)) 53 | } 54 | 55 | /// Fail the future with `e` and signal all the waiters (if any). 56 | public func reject(with err: Err) { 57 | transition(toState: .error(err)) 58 | } 59 | 60 | /// Cancel the future, preventing any completion callbacks from 61 | /// running if they haven't already. Does not affect the underlying 62 | /// work. 63 | public func cancel() { 64 | transition(toState: .canceled) 65 | } 66 | 67 | private func transition(toState: State) { 68 | mu.wait() 69 | switch state { 70 | case .pending: 71 | state = toState 72 | touch() 73 | default: 74 | () 75 | } 76 | mu.signal() 77 | } 78 | 79 | private func touch() { 80 | waiters.forEach { $0.signal() } 81 | waiters.removeAll() 82 | } 83 | 84 | /// Returns a new Future containing the result of applying `proc` to 85 | /// the data contained in the Future (once available). 86 | public func map(_ proc: @escaping @Sendable (Res) -> R) -> Future { 87 | let f = Future() 88 | DispatchQueue.global(qos: .default).async { 89 | switch self.wait(timeout: .distantFuture) { 90 | case .timedOut: 91 | preconditionFailure("unreachable") 92 | case .canceled: 93 | f.cancel() 94 | case .error(let error): 95 | f.reject(with: error) 96 | case .ok(let data): 97 | f.resolve(with: proc(data)) 98 | } 99 | } 100 | return f 101 | } 102 | 103 | /// Returns a new Future containing the result of applying `proc` to 104 | /// the error contained in the Future (once available and if any). 105 | public func mapError(_ proc: @escaping @Sendable (Err) -> E) -> Future { 106 | let f = Future() 107 | DispatchQueue.global(qos: .default).async { 108 | switch self.wait(timeout: .distantFuture) { 109 | case .timedOut: 110 | preconditionFailure("unreachable") 111 | case .canceled: 112 | f.cancel() 113 | case .error(let error): 114 | f.reject(with: proc(error)) 115 | case .ok(let data): 116 | f.resolve(with: data) 117 | } 118 | } 119 | return f 120 | } 121 | 122 | /// Chains two Futures together. 123 | public func andThen(_ proc: @escaping @Sendable (Res) -> Future) -> Future { 124 | let f = Future() 125 | DispatchQueue.global(qos: .default).async { 126 | switch self.wait(timeout: .distantFuture) { 127 | case .timedOut: 128 | preconditionFailure("unreachable") 129 | case .canceled: 130 | f.cancel() 131 | case .error(let err): 132 | f.reject(with: err) 133 | case .ok(let data): 134 | switch proc(data).wait(timeout: .distantFuture) { 135 | case .timedOut: 136 | preconditionFailure("unreachable") 137 | case .canceled: 138 | f.cancel() 139 | case .error(let err): 140 | f.reject(with: err) 141 | case .ok(let res): 142 | f.resolve(with: res) 143 | } 144 | } 145 | } 146 | return f 147 | } 148 | 149 | /// Executes `errorProc` or `completeProc` on `queue` depending on 150 | /// whether the Future succeeds or fails. The default error proc 151 | /// has no effect. 152 | public func sink( 153 | queue: DispatchQueue = DispatchQueue.main, 154 | onCancel cancelProc: @escaping @Sendable () -> Void = { }, 155 | onError errorProc: @escaping @Sendable (Err) -> Void = { _ in }, 156 | onComplete completeProc: @escaping @Sendable (Res) -> Void 157 | ) { 158 | DispatchQueue.global(qos: .default).async { 159 | let res = self.wait(timeout: .distantFuture) 160 | queue.async { 161 | switch res { 162 | case .timedOut: 163 | preconditionFailure("unreachable") 164 | case .canceled: 165 | cancelProc() 166 | case .error(let err): 167 | errorProc(err) 168 | case .ok(let res): 169 | completeProc(res) 170 | } 171 | } 172 | } 173 | } 174 | 175 | /// Executes `proc` on `queue` with the Future's data if and once 176 | /// available. 177 | public func onComplete( 178 | queue: DispatchQueue = DispatchQueue.main, 179 | _ proc: @escaping @Sendable (Res) -> Void 180 | ) { 181 | sink( 182 | queue: queue, 183 | onError: { error in 184 | defaultErrorHandlerMu.wait() 185 | defer { defaultErrorHandlerMu.signal() } 186 | defaultErrorHandler(error) 187 | }, 188 | onComplete: proc 189 | ) 190 | } 191 | 192 | /// Block the current thread until data is available. 193 | public func wait() throws -> Res { 194 | mu.wait() 195 | switch state { 196 | case .pending: 197 | let waiter = DispatchSemaphore(value: 0) 198 | waiters.append(waiter) 199 | mu.signal() 200 | waiter.wait() 201 | switch state { 202 | case .pending: 203 | preconditionFailure("impossible state") 204 | case .canceled: 205 | throw Canceled() 206 | case .ok(let res): 207 | return res 208 | case .error(let err): 209 | throw WaitError(error: err) 210 | } 211 | case .canceled: 212 | mu.signal() 213 | throw Canceled() 214 | case .ok(let res): 215 | mu.signal() 216 | return res 217 | case .error(let err): 218 | mu.signal() 219 | throw WaitError(error: err) 220 | } 221 | } 222 | 223 | /// Block the current thread until data is available or the timeout expires. 224 | public func wait(timeout t: DispatchTime) -> WaitResult { 225 | mu.wait() 226 | switch state { 227 | case .pending: 228 | let waiter = DispatchSemaphore(value: 0) 229 | waiters.append(waiter) 230 | mu.signal() 231 | switch waiter.wait(timeout: t) { 232 | case .success: 233 | switch state { 234 | case .pending: 235 | preconditionFailure("impossible state") 236 | case .canceled: 237 | return .canceled 238 | case .error(let err): 239 | return .error(err) 240 | case .ok(let res): 241 | return .ok(res) 242 | } 243 | case .timedOut: 244 | mu.wait() 245 | waiters.removeAll { $0 == waiter } 246 | mu.signal() 247 | return .timedOut 248 | } 249 | case .canceled: 250 | mu.signal() 251 | return .canceled 252 | case .error(let err): 253 | mu.signal() 254 | return .error(err) 255 | case .ok(let res): 256 | mu.signal() 257 | return .ok(res) 258 | } 259 | } 260 | } 261 | 262 | public class FutureUtil { 263 | /// Represents asyncified future errors. 264 | public enum AsyncError: LocalizedError { 265 | case error(String) 266 | 267 | public var errorDescription: String? { 268 | switch self { 269 | case .error(let s): 270 | return s 271 | } 272 | } 273 | } 274 | 275 | /// Converts a future into an async task. 276 | public static func asyncify(_ future: Future) async throws -> Res { 277 | return try await withTaskCancellationHandler { 278 | return try await withUnsafeThrowingContinuation { k in 279 | future.sink( 280 | queue: .global(qos: .userInitiated), 281 | onCancel: { k.resume(throwing: CancellationError()) }, 282 | onError: { k.resume(throwing: AsyncError.error($0)) }, 283 | onComplete: { k.resume(returning: $0) }) 284 | } 285 | } onCancel: { 286 | future.cancel() 287 | } 288 | } 289 | 290 | /// Returns a future that is immediately resolved. 291 | public static func resolved(with d: Res) -> Future { 292 | let fut = Future() 293 | fut.resolve(with: d) 294 | return fut 295 | } 296 | 297 | /// Returns a future that is immediately rejected. 298 | public static func rejected(with err: Err) -> Future { 299 | let fut = Future() 300 | fut.reject(with: err) 301 | return fut 302 | } 303 | 304 | /// Sets the default error handler that is used by `Future.onComplete`. 305 | public static func set(defaultErrorHandler hdl: @escaping (Any) -> Void) { 306 | defaultErrorHandlerMu.wait() 307 | defaultErrorHandler = hdl 308 | defaultErrorHandlerMu.signal() 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /Sources/NoiseBoot_iOS/NoiseBoot.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct NoiseBoot { 4 | public static let petiteURL = Bundle.module.url(forResource: "boot/arm64-ios/petite", withExtension: "boot")! 5 | public static let schemeURL = Bundle.module.url(forResource: "boot/arm64-ios/scheme", withExtension: "boot")! 6 | public static let racketURL = Bundle.module.url(forResource: "boot/arm64-ios/racket", withExtension: "boot")! 7 | } 8 | -------------------------------------------------------------------------------- /Sources/NoiseBoot_iOS/boot/arm64-ios/petite.boot: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:6c0048186029b60862f85c626ee29e51f79b5533340c271e085d78c579071ec6 3 | size 2930992 4 | -------------------------------------------------------------------------------- /Sources/NoiseBoot_iOS/boot/arm64-ios/racket.boot: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:bab9787b31dfe6feeac08169f506bcd5a91e9cb5b69becdca1469a9d40b98e05 3 | size 7043884 4 | -------------------------------------------------------------------------------- /Sources/NoiseBoot_iOS/boot/arm64-ios/scheme.boot: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:0525048e3ce384fbd7666345789524b9a1b9d40108decfbb7146ef8e24472b3a 3 | size 1615074 4 | -------------------------------------------------------------------------------- /Sources/NoiseBoot_macOS/NoiseBoot.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | #if arch(x86_64) 4 | let ARCH = "x86_64" 5 | #elseif arch(arm64) 6 | let ARCH = "arm64" 7 | #else 8 | #error("unsupported platform") 9 | #endif 10 | 11 | public struct NoiseBoot { 12 | public static let petiteURL = Bundle.module.url(forResource: "boot/\(ARCH)-macos/petite", withExtension: "boot")! 13 | public static let schemeURL = Bundle.module.url(forResource: "boot/\(ARCH)-macos/scheme", withExtension: "boot")! 14 | public static let racketURL = Bundle.module.url(forResource: "boot/\(ARCH)-macos/racket", withExtension: "boot")! 15 | } 16 | -------------------------------------------------------------------------------- /Sources/NoiseBoot_macOS/boot/arm64-macos/petite.boot: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:cefc5c493be08e48f16b99cfccf1ed37518179092fdf1323112afbb11ff605cc 3 | size 2526164 4 | -------------------------------------------------------------------------------- /Sources/NoiseBoot_macOS/boot/arm64-macos/racket.boot: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:c0ed11da148772c6ceece1b00a4603be80d09d99577953819efcaf1fb1c94e4c 3 | size 6638973 4 | -------------------------------------------------------------------------------- /Sources/NoiseBoot_macOS/boot/arm64-macos/scheme.boot: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:db32479eb2323c64c06160d3969941fdbff133818171ae1cbec1a0c4e4e1439a 3 | size 1325772 4 | -------------------------------------------------------------------------------- /Sources/NoiseBoot_macOS/boot/x86_64-macos/petite.boot: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:de2ad80f51c32a3fa33e878a9da4105b58f63898aa8dfe8b28bfdff5b8315806 3 | size 10939374 4 | -------------------------------------------------------------------------------- /Sources/NoiseBoot_macOS/boot/x86_64-macos/racket.boot: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:fc175747f1ff7e0ad8655324a475900a2f4efd3325c251fb48ae07c51d747f0d 3 | size 27643345 4 | -------------------------------------------------------------------------------- /Sources/NoiseBoot_macOS/boot/x86_64-macos/scheme.boot: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:47c75b29dd00e2b43a177f6478b02d1cdcf75e011e53b5501f1ad9e0fd0688e7 3 | size 7100105 4 | -------------------------------------------------------------------------------- /Sources/NoiseSerde/DataInputPort.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// An input port that reads from an in-memory buffer. 4 | public final class DataInputPort: InputPort { 5 | var data: Data 6 | var pos = 0 7 | 8 | public init(data: Data) { 9 | self.data = data 10 | } 11 | 12 | public func read(_ data: inout Data, count n: Int) -> Int { 13 | let n = min(self.data.count-pos, n) 14 | _ = data.withUnsafeMutableBytes { (buf: UnsafeMutableRawBufferPointer) in 15 | self.data.copyBytes(to: buf, from: pos.. UInt8 { 22 | let b = data[pos] 23 | pos += 1 24 | return b 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/NoiseSerde/DataOutputPort.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// An output port that buffers all writes into memory. 4 | public final class DataOutputPort: OutputPort { 5 | public var data: Data! 6 | 7 | public init(capacity: Int = 64*1024) { 8 | data = Data(capacity: capacity) 9 | } 10 | 11 | public func write(contentsOf data: Data) { 12 | self.data.append(data) 13 | } 14 | 15 | public func writeByte(_ b: UInt8) { 16 | self.data.append(contentsOf: [b]) 17 | } 18 | 19 | public func flush() {} 20 | } 21 | -------------------------------------------------------------------------------- /Sources/NoiseSerde/FileHandleInputPort.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Wraps a `FileHandle` to add buffered reading support. 4 | public final class FileHandleInputPort: InputPort { 5 | private let fd: Int32 6 | private let bufsize: Int 7 | private var buf: Data! 8 | private var cnt = 0 9 | private var idx = 0 10 | 11 | public init(withHandle h: FileHandle, andBufSize bufsize: Int = 8192) { 12 | self.fd = h.fileDescriptor 13 | self.buf = Data(count: bufsize) 14 | self.bufsize = bufsize 15 | } 16 | 17 | public func read(_ data: inout Data, count n: Int) -> Int { 18 | var pos = 0 19 | var want = n 20 | while want > 0 { 21 | let nread = data[pos.. Int { 32 | more() 33 | if cnt == 0 { 34 | return 0 35 | } 36 | let have = cnt - idx 37 | if have >= want { 38 | out.copyBytes(from: buf[idx.. UInt8 { 49 | repeat { 50 | more() 51 | } while (cnt == 0) 52 | let res = buf[idx] 53 | idx += 1 54 | return res 55 | } 56 | 57 | private func more() { 58 | if idx < cnt { 59 | return 60 | } 61 | cnt = buf.withUnsafeMutableBytes{ Darwin.read(fd, $0.baseAddress!, bufsize) } 62 | idx = 0 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Sources/NoiseSerde/FileHandleOutputPort.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Wraps a `FileHandle` to add buffered writing support. 4 | public final class FileHandleOutputPort: OutputPort { 5 | private let handle: FileHandle 6 | private var buf: Data! 7 | private let bufsize: Int 8 | private var cnt = 0 9 | 10 | public init(withHandle h: FileHandle, andBufSize bufsize: Int = 8192) { 11 | self.handle = h 12 | self.buf = Data(capacity: bufsize) 13 | self.bufsize = bufsize 14 | } 15 | 16 | public func write(contentsOf data: Data) { 17 | let remaining = bufsize - cnt 18 | if data.count > remaining { 19 | flush() 20 | try! handle.write(contentsOf: data) 21 | return 22 | } 23 | buf.append(data) 24 | cnt += data.count 25 | } 26 | 27 | public func writeByte(_ b: UInt8) { 28 | let remaining = bufsize - cnt 29 | if remaining == 0 { 30 | flush() 31 | } 32 | buf.append(b) 33 | cnt += 1 34 | } 35 | 36 | public func flush() { 37 | if cnt == 0 { 38 | return 39 | } 40 | try! handle.write(contentsOf: buf[0.. Int 7 | /// Reads up to `count` bytes from the handle into `out`, returning 8 | /// the number of bytes read. Returns 0 at EOF. 9 | func readByte() -> UInt8 10 | } 11 | 12 | public protocol OutputPort { 13 | /// Buffers `data` into memory if there is sufficient capacity. 14 | /// Otherwise, flushes any previously-buffered data and writes the 15 | /// new data to the handle. 16 | func write(contentsOf data: Data) 17 | /// Buffers a single byte into memory if there is sufficient 18 | /// capacity. Otherwise, flushes any previously-buffered data and 19 | /// then buffers the byte. 20 | func writeByte(_ b: UInt8) 21 | /// Writes any buffered data to the handle. 22 | func flush() 23 | } 24 | -------------------------------------------------------------------------------- /Sources/NoiseSerde/Serde.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// The protocol for readable serde values. 4 | public protocol Readable { 5 | static func read(from inp: InputPort, using buf: inout Data) -> Self 6 | } 7 | 8 | /// The protocol for writable serde values. 9 | public protocol Writable { 10 | func write(to out: OutputPort) 11 | } 12 | 13 | // MARK: - Bool 14 | extension Bool: Readable, Writable { 15 | public static func read(from inp: InputPort, using buf: inout Data) -> Bool { 16 | return inp.readByte() == 1 17 | } 18 | 19 | public func write(to out: OutputPort) { 20 | out.writeByte(self ? 1 : 0) 21 | } 22 | } 23 | 24 | // MARK: - Data 25 | extension Data: Readable, Writable { 26 | public static func read(from inp: InputPort, using buf: inout Data) -> Data { 27 | let vlen = Varint.read(from: inp, using: &buf) 28 | assert(vlen >= 0) 29 | if vlen == 0 { 30 | return Data(count: 0) 31 | } 32 | let len = Int(vlen) 33 | buf.grow(upTo: len) 34 | let nread = inp.read(&buf, count: len) 35 | if nread < len { 36 | preconditionFailure("Data: received \(nread) bytes but expected \(len)") 37 | } 38 | return try! buf.withUnsafeBytes { ptr throws in 39 | return Data(bytes: ptr.baseAddress!, count: len) 40 | } 41 | } 42 | 43 | public func write(to out: OutputPort) { 44 | Varint(count).write(to: out) 45 | out.write(contentsOf: self) 46 | } 47 | } 48 | 49 | // MARK: - Float32 50 | extension Float32: Readable, Writable { 51 | public static func read(from inp: InputPort, using buf: inout Data) -> Float32 { 52 | return Float32(bitPattern: ( 53 | UInt32(inp.readByte()) << 24 | 54 | UInt32(inp.readByte()) << 16 | 55 | UInt32(inp.readByte()) << 8 | 56 | UInt32(inp.readByte()) 57 | )) 58 | } 59 | 60 | public func write(to out: OutputPort) { 61 | let bits = self.bitPattern 62 | out.writeByte(UInt8(truncatingIfNeeded: bits >> 24 & 0xFF)) 63 | out.writeByte(UInt8(truncatingIfNeeded: bits >> 16 & 0xFF)) 64 | out.writeByte(UInt8(truncatingIfNeeded: bits >> 8 & 0xFF)) 65 | out.writeByte(UInt8(truncatingIfNeeded: bits & 0xFF)) 66 | } 67 | } 68 | 69 | // MARK: - Float64 70 | extension Float64: Readable, Writable { 71 | public static func read(from inp: InputPort, using buf: inout Data) -> Float64 { 72 | return Float64(bitPattern: ( 73 | UInt64(inp.readByte()) << 56 | 74 | UInt64(inp.readByte()) << 48 | 75 | UInt64(inp.readByte()) << 40 | 76 | UInt64(inp.readByte()) << 32 | 77 | UInt64(inp.readByte()) << 24 | 78 | UInt64(inp.readByte()) << 16 | 79 | UInt64(inp.readByte()) << 8 | 80 | UInt64(inp.readByte()) 81 | )) 82 | } 83 | 84 | public func write(to out: OutputPort) { 85 | let bits = self.bitPattern 86 | out.writeByte(UInt8(truncatingIfNeeded: bits >> 56 & 0xFF)) 87 | out.writeByte(UInt8(truncatingIfNeeded: bits >> 48 & 0xFF)) 88 | out.writeByte(UInt8(truncatingIfNeeded: bits >> 40 & 0xFF)) 89 | out.writeByte(UInt8(truncatingIfNeeded: bits >> 32 & 0xFF)) 90 | out.writeByte(UInt8(truncatingIfNeeded: bits >> 24 & 0xFF)) 91 | out.writeByte(UInt8(truncatingIfNeeded: bits >> 16 & 0xFF)) 92 | out.writeByte(UInt8(truncatingIfNeeded: bits >> 8 & 0xFF)) 93 | out.writeByte(UInt8(truncatingIfNeeded: bits & 0xFF)) 94 | } 95 | } 96 | 97 | // MARK: - Int16 98 | extension Int16: Readable, Writable { 99 | public static func read(from inp: InputPort, using buf: inout Data) -> Int16 { 100 | return Int16(bitPattern: ( 101 | UInt16(inp.readByte()) << 8 | 102 | UInt16(inp.readByte()) 103 | )) 104 | } 105 | 106 | public func write(to out: OutputPort) { 107 | out.writeByte(UInt8(truncatingIfNeeded: self >> 8 & 0xFF)) 108 | out.writeByte(UInt8(truncatingIfNeeded: self & 0xFF)) 109 | } 110 | } 111 | 112 | // MARK: - Int32 113 | extension Int32: Readable, Writable { 114 | public static func read(from inp: InputPort, using buf: inout Data) -> Int32 { 115 | return Int32(bitPattern: ( 116 | UInt32(inp.readByte()) << 24 | 117 | UInt32(inp.readByte()) << 16 | 118 | UInt32(inp.readByte()) << 8 | 119 | UInt32(inp.readByte()) 120 | )) 121 | } 122 | 123 | public func write(to out: OutputPort) { 124 | out.writeByte(UInt8(truncatingIfNeeded: self >> 24 & 0xFF)) 125 | out.writeByte(UInt8(truncatingIfNeeded: self >> 16 & 0xFF)) 126 | out.writeByte(UInt8(truncatingIfNeeded: self >> 8 & 0xFF)) 127 | out.writeByte(UInt8(truncatingIfNeeded: self & 0xFF)) 128 | } 129 | } 130 | 131 | // MARK: - UInt16 132 | extension UInt16: Readable, Writable { 133 | public static func read(from inp: InputPort, using buf: inout Data) -> UInt16 { 134 | return UInt16(bitPattern: ( 135 | Int16(inp.readByte()) << 8 | 136 | Int16(inp.readByte()) 137 | )) 138 | } 139 | 140 | public func write(to out: OutputPort) { 141 | out.writeByte(UInt8(truncatingIfNeeded: self >> 8 & 0xFF)) 142 | out.writeByte(UInt8(truncatingIfNeeded: self & 0xFF)) 143 | } 144 | } 145 | 146 | // MARK: - UInt32 147 | extension UInt32: Readable, Writable { 148 | public static func read(from inp: InputPort, using buf: inout Data) -> UInt32 { 149 | return UInt32(bitPattern: ( 150 | Int32(inp.readByte()) << 24 | 151 | Int32(inp.readByte()) << 16 | 152 | Int32(inp.readByte()) << 8 | 153 | Int32(inp.readByte()) 154 | )) 155 | } 156 | 157 | public func write(to out: OutputPort) { 158 | out.writeByte(UInt8(truncatingIfNeeded: self >> 24 & 0xFF)) 159 | out.writeByte(UInt8(truncatingIfNeeded: self >> 16 & 0xFF)) 160 | out.writeByte(UInt8(truncatingIfNeeded: self >> 8 & 0xFF)) 161 | out.writeByte(UInt8(truncatingIfNeeded: self & 0xFF)) 162 | } 163 | } 164 | 165 | // MARK: - Varint 166 | public typealias Varint = Int64 167 | 168 | extension Varint: Readable, Writable { 169 | public static func read(from inp: InputPort, using buf: inout Data) -> Varint { 170 | var s = Varint(0) 171 | var n = Varint(0) 172 | while true { 173 | let b = inp.readByte() 174 | let x = Int64(b) 175 | if x & 0x80 == 0 { 176 | n += x << s 177 | break 178 | } 179 | n += (x & 0x7F) << s 180 | s += 7 181 | } 182 | if n & 1 == 0 { 183 | return n >> 1 184 | } 185 | return ~(n >> 1) 186 | } 187 | 188 | public func write(to out: OutputPort) { 189 | var n = (self << 1) ^ (self < 0 ? -1 : 0) 190 | while true { 191 | let (q, r) = n.quotientAndRemainder(dividingBy: 0x80) 192 | if q == 0 { 193 | out.writeByte(UInt8(truncatingIfNeeded: r)) 194 | break 195 | } else { 196 | out.writeByte(UInt8(truncatingIfNeeded: r|0x80)) 197 | n = q 198 | } 199 | } 200 | } 201 | } 202 | 203 | // MARK: - UVarint 204 | public typealias UVarint = UInt64 205 | 206 | extension UVarint: Readable, Writable { 207 | public static func read(from inp: InputPort, using buf: inout Data) -> UVarint { 208 | var s = UVarint(0) 209 | var n = UVarint(0) 210 | while true { 211 | let b = inp.readByte() 212 | let x = UInt64(b) 213 | if x & 0x80 == 0 { 214 | n += x << s 215 | break 216 | } 217 | n += (x & 0x7F) << s 218 | s += 7 219 | } 220 | return n 221 | } 222 | 223 | public func write(to out: OutputPort) { 224 | var n = self 225 | while true { 226 | let (q, r) = n.quotientAndRemainder(dividingBy: 0x80) 227 | if q == 0 { 228 | out.writeByte(UInt8(truncatingIfNeeded: r)) 229 | break 230 | } else { 231 | out.writeByte(UInt8(truncatingIfNeeded: r|0x80)) 232 | n = q 233 | } 234 | } 235 | } 236 | } 237 | 238 | // MARK: - String 239 | extension String: Readable, Writable { 240 | public static func read(from inp: InputPort, using buf: inout Data) -> String { 241 | let vlen = Varint.read(from: inp, using: &buf) 242 | assert(vlen >= 0) 243 | if vlen == 0 { 244 | return "" 245 | } 246 | let len = Int(vlen) 247 | buf.grow(upTo: len) 248 | let nread = inp.read(&buf, count: len) 249 | if nread < len { 250 | preconditionFailure("String: received \(nread) bytes, but expected \(len)") 251 | } 252 | guard let str = String(data: buf[0.. [Element] { 271 | let len = Varint.read(from: inp, using: &buf) 272 | assert(len >= 0) 273 | if len == 0 { 274 | return [] 275 | } 276 | var res = [Element]() 277 | res.reserveCapacity(Int(len)) 278 | for _ in 0.. [Key: Value] { 295 | let len = Varint.read(from: inp, using: &buf) 296 | assert(len >= 0) 297 | if len == 0 { 298 | return [:] 299 | } 300 | var res = [Key: Value]() 301 | res.reserveCapacity(Int(len)) 302 | for _ in 0.. Wrapped? { 322 | if inp.readByte() == 0 { 323 | return nil 324 | } 325 | return Wrapped.read(from: inp, using: &buf) 326 | } 327 | 328 | public func write(to out: OutputPort) { 329 | switch self { 330 | case .none: 331 | out.writeByte(0) 332 | case .some(let v): 333 | out.writeByte(1) 334 | v.write(to: out) 335 | } 336 | } 337 | } 338 | 339 | // MARK: - Data 340 | fileprivate extension Data { 341 | mutating func grow(upTo n: Int) { 342 | let want = n - count 343 | if want <= 0 { 344 | return 345 | } 346 | reserveCapacity(n) 347 | append(Data(count: want)) 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /Template/BackendExtensions.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Backend { 4 | static let shared = Backend( 5 | withZo: Bundle.main.url(forResource: "res/core", withExtension: "zo")!, 6 | andMod: "main", 7 | andProc: "main" 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /Template/Entitlements/00-Application.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.apple.security.app-sandbox 7 | 8 | com.apple.security.cs.allow-jit 9 | 10 | com.apple.security.cs.allow-unsigned-executable-memory 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Template/Entitlements/01-dylib.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.apple.security.app-sandbox 7 | 8 | com.apple.security.inherit 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Template/Makefile: -------------------------------------------------------------------------------- 1 | APP_SRC=AppNameHere # FIXME 2 | RKT_SRC=core 3 | RKT_FILES=$(shell find ${RKT_SRC} -name '*.rkt') 4 | RKT_MAIN_ZO=${RKT_SRC}/compiled/main_rkt.zo 5 | 6 | RESOURCES_PATH=${APP_SRC}/res 7 | RUNTIME_NAME=runtime 8 | RUNTIME_PATH=${RESOURCES_PATH}/${RUNTIME_NAME} 9 | MANUAL_PATH=${RESOURCES_PATH}/manual 10 | 11 | CORE_ZO=${RESOURCES_PATH}/core.zo 12 | 13 | .PHONY: all 14 | all: ${CORE_ZO} ${APP_SRC}/Backend.swift 15 | 16 | .PHONY: clean 17 | clean: 18 | rm -fr ${RESOURCES_PATH} 19 | 20 | # When building for iOS, replace `raco` with `./bin/pbraco`. 21 | 22 | ${RKT_MAIN_ZO}: ${RKT_FILES} 23 | raco make -j 16 -v ${RKT_SRC}/main.rkt 24 | 25 | ${CORE_ZO}: ${RKT_MAIN_ZO} 26 | mkdir -p ${RESOURCES_PATH} 27 | rm -fr ${RUNTIME_PATH} 28 | raco ctool \ 29 | --runtime ${RUNTIME_PATH} \ 30 | --runtime-access ${RUNTIME_NAME} \ 31 | --mods $@ ${RKT_SRC}/main.rkt 32 | 33 | ${APP_SRC}/Backend.swift: ${CORE_ZO} 34 | raco noise-serde-codegen ${RKT_SRC}/main.rkt > $@ 35 | 36 | ${MANUAL_PATH}/index.html: manual/*.scrbl 37 | raco scribble --html --dest ${MANUAL_PATH} +m manual/index.scrbl 38 | 39 | website/manual/index.html: manual/*.scrbl 40 | make -C website manual/index.html 41 | -------------------------------------------------------------------------------- /Template/README.md: -------------------------------------------------------------------------------- 1 | # Templates 2 | 3 | This folder contains scripts and build files that Noise projects 4 | typically use. You can pick and choose from them and adapt them for 5 | your projects. 6 | -------------------------------------------------------------------------------- /Template/bin/pbracket: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Helper to run Racket in cross-compilation mode with a portable 4 | # bytecode target. Expects the PBRACKET_ROOT environment variable to 5 | # be set before running. 6 | 7 | set -euo pipefail 8 | 9 | RACKET_DIR="${PBRACKET_ROOT}/racket" 10 | BUILD_DIR="${RACKET_DIR}/src/build/cs/c" 11 | COMPILED_DIR="${BUILD_DIR}/compiled" 12 | 13 | racket \ 14 | --cross-compiler tpb64l "$BUILD_DIR" \ 15 | -MCR "$COMPILED_DIR": \ 16 | -G "${RACKET_DIR}/etc" \ 17 | -X "${RACKET_DIR}/collects" \ 18 | "$@" 19 | -------------------------------------------------------------------------------- /Template/bin/pbraco: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | HERE="$(dirname "$0")" 6 | "$HERE/pbracket" -N raco -U -l- raco "$@" 7 | -------------------------------------------------------------------------------- /Template/bin/sign-dylibs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # On macOS, add this script as an early build phase to sign 4 | # distributed dylibs. Make sure to disable "User Script Sandboxing" 5 | # under "Build Settings" > "Build Options" in the Xcode target 6 | # configuration. 7 | 8 | set -euo pipefail 9 | 10 | while read -r path; do 11 | filename=$(basename "$path") 12 | libname=$(echo "$filename" | cut -d. -f1) 13 | codesign --remove-signature "$path" 14 | codesign \ 15 | --timestamp \ 16 | --entitlements="${PROJECT_DIR}/core/dylib.entitlements" \ 17 | --sign "${EXPANDED_CODE_SIGN_IDENTITY}" \ 18 | -i "${PRODUCT_BUNDLE_IDENTIFIER}.${libname}" \ 19 | -o runtime \ 20 | "$path" 21 | done < <(find "${PROJECT_DIR}/${PROJECT_NAME}/res" -name '*.dylib') 22 | -------------------------------------------------------------------------------- /Tests/NoiseTest/FutureTest.swift: -------------------------------------------------------------------------------- 1 | import Dispatch 2 | import NoiseBackend 3 | import XCTest 4 | 5 | class FutureTests: XCTestCase { 6 | func testRejected() { 7 | let f = FutureUtil.rejected(with: "failed") 8 | XCTAssertThrowsError(try f.wait()) 9 | } 10 | 11 | func testResolved() { 12 | let f = FutureUtil.resolved(with: 42) 13 | let r = try! f.wait() 14 | XCTAssertEqual(42, r) 15 | } 16 | 17 | func testReject() { 18 | let f = Future() 19 | DispatchQueue.global(qos: .background).async { 20 | f.reject(with: "failed") 21 | } 22 | XCTAssertThrowsError(try f.wait()) 23 | } 24 | 25 | func testResolve() { 26 | let f = Future() 27 | DispatchQueue.global(qos: .background).async { 28 | f.resolve(with: 42) 29 | } 30 | let r = try! f.wait() 31 | XCTAssertEqual(42, r) 32 | } 33 | 34 | func testMap() { 35 | let f = Future() 36 | let g = f.map { $0 * 2 } 37 | f.resolve(with: 42) 38 | XCTAssertEqual(84, try! g.wait()) 39 | } 40 | 41 | func testMapError() { 42 | let f = Future() 43 | f.reject(with: "failed") 44 | let g = f.mapError { $0.uppercased() } 45 | switch g.wait(timeout: .now() + 0.5) { 46 | case .error(let err): 47 | XCTAssertEqual("FAILED", err) 48 | default: 49 | XCTFail() 50 | } 51 | } 52 | 53 | func testAndThen() { 54 | let f = Future() 55 | f.resolve(with: "hello") 56 | let g: Future = f.andThen { str in 57 | let g = Future() 58 | g.resolve(with: str.count) 59 | return g 60 | } 61 | XCTAssertEqual(5, try! g.wait()) 62 | } 63 | 64 | func testTimeout() { 65 | let f = Future() 66 | switch f.wait(timeout: .now() + 0.5) { 67 | case .timedOut: 68 | XCTAssertTrue(true) 69 | default: 70 | XCTFail() 71 | } 72 | } 73 | 74 | func testCancelImmediately() { 75 | let f = Future() 76 | f.cancel() 77 | switch f.wait(timeout: .now() + 0.1) { 78 | case .canceled: 79 | XCTAssertTrue(true) 80 | default: 81 | XCTFail() 82 | } 83 | } 84 | 85 | func testCancelConcurrently() { 86 | let f = Future() 87 | DispatchQueue.global(qos: .background).async { 88 | Thread.sleep(forTimeInterval: 0.5) 89 | f.resolve(with: 42) 90 | } 91 | f.cancel() 92 | switch f.wait(timeout: .now() + 1.0) { 93 | case .canceled: 94 | XCTAssertTrue(true) 95 | default: 96 | XCTFail() 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Tests/NoiseTest/Modules/.gitignore: -------------------------------------------------------------------------------- 1 | mods.zo 2 | runtime/ 3 | -------------------------------------------------------------------------------- /Tests/NoiseTest/Modules/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: deps mods.zo 3 | 4 | .PHONY: deps 5 | deps: 6 | raco pkg install --auto --skip-installed http-easy-lib 7 | 8 | mods.zo: *.rkt 9 | raco ctool \ 10 | --runtime runtime \ 11 | --mods $@ \ 12 | callout.rkt fib.rkt http.rkt loud.rkt bytes.rkt 13 | 14 | .PHONY: clean 15 | clean: 16 | rm -f mods.zo 17 | -------------------------------------------------------------------------------- /Tests/NoiseTest/Modules/bytes.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (provide 4 | get-bytes) 5 | 6 | (define (get-bytes) 7 | (bytes 1 2 128 255)) 8 | -------------------------------------------------------------------------------- /Tests/NoiseTest/Modules/callout.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require ffi/unsafe 4 | noise/unsafe/callout) 5 | 6 | (provide 7 | install-callout! 8 | exec-callout) 9 | 10 | (define callout 11 | (make-callout-box (_fun _int _bytes -> _void))) 12 | 13 | (define (install-callout! addr) 14 | (callout-box-install! callout addr)) 15 | 16 | (define (exec-callout) 17 | (callout 5 #"hello")) 18 | -------------------------------------------------------------------------------- /Tests/NoiseTest/Modules/cookie: -------------------------------------------------------------------------------- 1 | cookie 2 | -------------------------------------------------------------------------------- /Tests/NoiseTest/Modules/fib.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (provide fib) 4 | 5 | (define (fib n) 6 | (if (< n 2) 7 | n 8 | (+ (fib (- n 2)) 9 | (fib (- n 1))))) 10 | -------------------------------------------------------------------------------- /Tests/NoiseTest/Modules/http.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require (prefix-in http: net/http-easy)) 4 | 5 | (provide get) 6 | 7 | (define (get uri) 8 | (define res (http:get uri)) 9 | (values 10 | (http:response-status-code res) 11 | (http:response-body res))) 12 | -------------------------------------------------------------------------------- /Tests/NoiseTest/Modules/loud.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require racket/format) 4 | 5 | (provide exclaim) 6 | 7 | (define (exclaim s) 8 | (string->bytes/utf-8 (~a s "!!!"))) 9 | -------------------------------------------------------------------------------- /Tests/NoiseTest/RacketTest.swift: -------------------------------------------------------------------------------- 1 | import Noise 2 | import XCTest 3 | 4 | nonisolated(unsafe) var r: Racket! 5 | 6 | class RacketTest: XCTestCase { 7 | override class func setUp() { 8 | // Runtime-paths are relative to `(find-system-path 'exec-file)`, 9 | // so our bundle needs to contain an `exec-file` (that doesn't 10 | // have to actually be executable) from which the runtime folder 11 | // path can be derived. So, the easiest solution in this case is 12 | // to add a "cookie" file whose sole purpose is to help us work 13 | // out the paths. 14 | let cookiePath = Bundle.module.resourceURL! 15 | .appendingPathComponent("Modules") 16 | .appendingPathComponent("cookie") 17 | .path 18 | 19 | r = Racket(execPath: cookiePath) 20 | r.bracket { 21 | r.load(zo: Bundle.module.url(forResource: "Modules/mods", withExtension: "zo")!) 22 | } 23 | } 24 | 25 | override class func tearDown() { 26 | r.destroy() 27 | } 28 | 29 | func testApplication() { 30 | r.bracket { 31 | let mod = Val.cons(Val.symbol("quote"), Val.cons(Val.symbol("fib"), Val.null)) 32 | let fib = r.require(Val.symbol("fib"), from: mod).car()! 33 | XCTAssertEqual(fib.apply(Val.cons(Val.fixnum(0), Val.null))!.car()!.fixnum(), 0) 34 | XCTAssertEqual(fib.apply(Val.cons(Val.fixnum(1), Val.null))!.car()!.fixnum(), 1) 35 | XCTAssertEqual(fib.apply(Val.cons(Val.fixnum(2), Val.null))!.car()!.fixnum(), 1) 36 | XCTAssertEqual(fib.apply(Val.cons(Val.fixnum(8), Val.null))!.car()!.fixnum(), 21) 37 | } 38 | } 39 | 40 | func testBytestring() { 41 | r.bracket { 42 | let mod = Val.cons(Val.symbol("quote"), Val.cons(Val.symbol("loud"), Val.null)) 43 | let exclaim = r.require(Val.symbol("exclaim"), from: mod).car()! 44 | let res = exclaim.apply(Val.cons(Val.string("hello"), Val.null))! 45 | XCTAssertEqual(res.car()?.bytestring()!, "hello!!!") 46 | } 47 | } 48 | 49 | func testBytevector() { 50 | r.bracket { 51 | let mod = Val.cons(Val.symbol("quote"), Val.cons(Val.symbol("bytes"), Val.null)) 52 | let get = r.require(Val.symbol("get-bytes"), from: mod).car()! 53 | let res = get.apply(Val.null)!.car()!.bytevector()!.map({ UInt8(bitPattern: $0) }) 54 | XCTAssertEqual(res, [1, 2, 128, 255]) 55 | } 56 | } 57 | 58 | func testHttp() { 59 | r.bracket { 60 | let mod = Val.cons(Val.symbol("quote"), Val.cons(Val.symbol("http"), Val.null)) 61 | let proc = r.require(Val.symbol("get"), from: mod).car()! 62 | let res = proc.apply(Val.cons(Val.string("defn.io"), Val.null))! 63 | let status = res.car()!.fixnum()! 64 | let content = res.cdr()!.car()!.bytestring()! 65 | XCTAssertEqual(status, 200) 66 | 67 | let re = try! NSRegularExpression(pattern: "Posts — defn.io") 68 | let matches = re.numberOfMatches(in: content, range: NSMakeRange(0, content.count)) 69 | XCTAssertEqual(matches, 1) 70 | } 71 | } 72 | 73 | func testCallout() { 74 | r.bracket { 75 | let mod = Val.cons(Val.symbol("quote"), Val.cons(Val.symbol("callout"), Val.null)).locked() 76 | defer { mod.unlock() } 77 | 78 | let install = r.require(Val.symbol("install-callout!"), from: mod).unsafeCar() 79 | let ptr = unsafeBitCast(calloutExampleProc, to: Optional.self)! 80 | install.unsafeApply(Val.cons(Val.pointer(ptr), Val.null)) 81 | 82 | let call = r.require(Val.symbol("exec-callout"), from: mod).unsafeCar() 83 | call.unsafeApply(Val.null) 84 | } 85 | XCTAssertEqual(calloutResult, "hello") 86 | } 87 | } 88 | 89 | nonisolated(unsafe) fileprivate var calloutResult: String? 90 | nonisolated(unsafe) fileprivate var calloutExampleProc: @convention(c) (Int, UnsafePointer) -> Void = { len, ptr in 91 | let data = Data(bytes: ptr, count: len) 92 | calloutResult = String(data: data, encoding: .utf8)! 93 | } 94 | -------------------------------------------------------------------------------- /Tests/NoiseTest/SerdeTest.swift: -------------------------------------------------------------------------------- 1 | import NoiseSerde 2 | import XCTest 3 | 4 | class SerdeTests: XCTestCase { 5 | func testInputPortBuffering() { 6 | let bufsizes = [1, 2, 4, 8, 1024] 7 | for bufsize in bufsizes { 8 | let p = Pipe() 9 | let inp = FileHandleInputPort(withHandle: p.fileHandleForReading, andBufSize: bufsize) 10 | let out = FileHandleOutputPort(withHandle: p.fileHandleForWriting) 11 | out.write(contentsOf: "hello".data(using: .utf8)!) 12 | out.flush() 13 | var buf = Data(count: 8192) 14 | let nread = inp.read(&buf, count: 5) 15 | XCTAssertEqual(5, nread) 16 | XCTAssertEqual("hello", String(data: buf[0..<5], encoding: .utf8)) 17 | } 18 | } 19 | 20 | func testFloat64Roundtrip() { 21 | let p = Pipe() 22 | let inp = FileHandleInputPort(withHandle: p.fileHandleForReading) 23 | let out = FileHandleOutputPort(withHandle: p.fileHandleForWriting) 24 | let tests: [Float64] = [0, 0.5, 1.25, -5.0] 25 | var buf = Data(count: 8192) 26 | for n in tests { 27 | n.write(to: out) 28 | out.flush() 29 | XCTAssertEqual(n, Float64.read(from: inp, using: &buf)) 30 | } 31 | } 32 | 33 | func testInt32Roundtrip() { 34 | let p = Pipe() 35 | let inp = FileHandleInputPort(withHandle: p.fileHandleForReading) 36 | let out = FileHandleOutputPort(withHandle: p.fileHandleForWriting) 37 | let tests: [Int32] = [0, 0xFF, -0xFF, 0x7FFFFFFF, -0x7FFFFFFF] 38 | var buf = Data(count: 8192) 39 | for n in tests { 40 | n.write(to: out) 41 | out.flush() 42 | XCTAssertEqual(n, Int32.read(from: inp, using: &buf)) 43 | } 44 | } 45 | 46 | func testVarintRoundtrip() { 47 | let p = Pipe() 48 | let inp = FileHandleInputPort(withHandle: p.fileHandleForReading) 49 | let out = FileHandleOutputPort(withHandle: p.fileHandleForWriting) 50 | let tests: [Varint] = [ 51 | 0x0, 0x1, -0x1, 0x7F, -0x7F, 0x80, -0x80, 52 | 0xFF, -0xFF, 0xFFF, -0xFFF, 0xFFFFF, -0xFFFFF, 53 | ] 54 | var buf = Data(count: 8192) 55 | for n in tests { 56 | n.write(to: out) 57 | out.flush() 58 | XCTAssertEqual(n, Varint.read(from: inp, using: &buf)) 59 | } 60 | } 61 | 62 | func testUVarintRoundtrip() { 63 | let p = Pipe() 64 | let inp = FileHandleInputPort(withHandle: p.fileHandleForReading) 65 | let out = FileHandleOutputPort(withHandle: p.fileHandleForWriting) 66 | let tests: [UVarint] = [0x0, 0x1, 0x7F, 0x80, 0xFF, 0xFFF, 0xFFFFF] 67 | var buf = Data(count: 8192) 68 | for n in tests { 69 | n.write(to: out) 70 | out.flush() 71 | XCTAssertEqual(n, UVarint.read(from: inp, using: &buf)) 72 | } 73 | } 74 | 75 | func testArrayRoundtrip() { 76 | let p = Pipe() 77 | let inp = FileHandleInputPort(withHandle: p.fileHandleForReading) 78 | let out = FileHandleOutputPort(withHandle: p.fileHandleForWriting) 79 | let data: [String] = ["hello", "there"] 80 | var buf = Data(count: 8192) 81 | data.write(to: out) 82 | out.flush() 83 | let res = [String].read(from: inp, using: &buf) 84 | XCTAssertEqual(data, res) 85 | } 86 | 87 | func testOptionalRoundtrip() { 88 | let p = Pipe() 89 | let inp = FileHandleInputPort(withHandle: p.fileHandleForReading) 90 | let out = FileHandleOutputPort(withHandle: p.fileHandleForWriting) 91 | var buf = Data(count: 8192) 92 | 93 | // empty 94 | var data: String? 95 | data.write(to: out) 96 | out.flush() 97 | XCTAssertEqual(data, String?.read(from: inp, using: &buf)) 98 | 99 | // full 100 | data = "hello, world" 101 | data.write(to: out) 102 | out.flush() 103 | XCTAssertEqual(data, String?.read(from: inp, using: &buf)) 104 | } 105 | 106 | func testStringSmallBuffer() { 107 | let p = Pipe() 108 | let s = "hello, world!" 109 | let inp = FileHandleInputPort(withHandle: p.fileHandleForReading) 110 | let out = FileHandleOutputPort(withHandle: p.fileHandleForWriting) 111 | var buf = Data(count: 5) 112 | s.write(to: out) 113 | out.flush() 114 | XCTAssertEqual(s, String.read(from: inp, using: &buf)) 115 | XCTAssertEqual(s.count, buf.count) 116 | } 117 | 118 | func testStringSmallBufferViaDataPorts() { 119 | let s = "hello, world!" 120 | let out = DataOutputPort() 121 | s.write(to: out) 122 | let inp = DataInputPort(data: out.data) 123 | var buf = Data(count: 5) 124 | XCTAssertEqual(s, String.read(from: inp, using: &buf)) 125 | XCTAssertEqual(s.count, buf.count) 126 | } 127 | 128 | func testStringRoundtripPerformance() { 129 | let p = Pipe() 130 | let s = "hello, world!" 131 | let inp = FileHandleInputPort(withHandle: p.fileHandleForReading) 132 | let out = FileHandleOutputPort(withHandle: p.fileHandleForWriting) 133 | var buf = Data(count: 8192) 134 | let opts = XCTMeasureOptions() 135 | opts.iterationCount = 1000 136 | measure(options: opts) { 137 | s.write(to: out) 138 | out.flush() 139 | let _ = String.read(from: inp, using: &buf) 140 | } 141 | } 142 | 143 | func testDictionaryRoundtrip() { 144 | let p = Pipe() 145 | let v = [ 146 | "a": UVarint(42), 147 | "b": UVarint(10) 148 | ] 149 | let inp = FileHandleInputPort(withHandle: p.fileHandleForReading) 150 | let out = FileHandleOutputPort(withHandle: p.fileHandleForWriting) 151 | var buf = Data(count: 8192) 152 | v.write(to: out) 153 | out.flush() 154 | let r = [String: UVarint].read(from: inp, using: &buf) 155 | XCTAssertEqual(v, r) 156 | } 157 | 158 | func testDictionaryRoundtripViaDataPorts() { 159 | let v = [ 160 | "a": UVarint(42), 161 | "b": UVarint(10), 162 | ] 163 | let out = DataOutputPort() 164 | v.write(to: out) 165 | let inp = DataInputPort(data: out.data) 166 | var buf = Data(count: 8192) 167 | let r = [String: UVarint].read(from: inp, using: &buf) 168 | XCTAssertEqual(v, r) 169 | } 170 | } 171 | --------------------------------------------------------------------------------