Thecontents of index_browser.ts and index_node.ts can be shockingly short as their only purpose is to set up exports. Below we see index_node.ts which aliases the NativeHighwayHash class to HighwayHash so that consumers can remain functionally unaware of the underlying type.
It may seem odd to stick a synchronous function behind async and have it return an IHash instead of the concrete type, but this is all done so that WasmHighwayHash and NativeHighwayHash operate exactly the same for the user.
This cost can be partially mitigated when the loading of a module needs to be asynchronous but the construction can be synchronous. In the case of highwayhasher, construction of a hash from key data is synchronous for both node and browsers. Splitting these instructions can make it more apparent that the act of hashing data is done synchronously (the following example is contrived but makes more sense when embedded in a larger application):
In addition to massaging function signatures to be equivalent between implementations, the typescript wrappers around the underlying rust bindings also take care of some of the validation and errors as these tend to be more succinctly represented in typescript than rust bindings. For instance it is easier to write rust bindings that assume hash initialization takes a non-null byte array of length 0 (to trigger the default) or 32. Then the wrappers can guard against the other possibilities:
There are three options for implementing addons: N-API, NAN (Native Abstractions for Node.js), or direct use of internal V8, libuv and Node.js libraries. Unless there is a need for direct access to functionality which is not exposed by N-API, use N-API.
I want to take a moment and extol these rust N-API projects. The projects are actively developed and the maintainers are quick to respond to questions / bug reports and are courteous. I tend to hold rust projects to a higher standard and these projects were still able to stand above the rest. Despite my decision to go with napi-rs for highwayhasher, I think any of these crates are viable for an N-API project: neon for the popularity, napi-rs for the minimalism, or node-bindgen for the ergonomics.
The trick is to write jest tests and execute them as usual with the node environment, and then execute the same tests with karmatic, a zero-config browser test environment with a jest-like API (it is really jasmine). Karmatic is truly no-config and since it uses webpack under the covers, it verifies that the browser directive given in the package.json resolves correctly.
With the native implementation relying on platform specifics, creating a release workflow is critical. Github Actions is utilized so that we have one platform to build our windows, linux, and mac libraries. Here is the Github workflow:
There are more end user systems than the machines github provides. For instance, github does not provide arm machines. The Rust community has an established way to cross compile assets to other architectures: cross.
Building the node native addons directly (they are, after all, just plain dynamically linked libraries) with cargo / cross meant that I could drop the napi cli dependency. Some additional tweaks were needed:
A benefit of shipping everything together precompiled is that there are no post install steps. No compilation tools needed, no need to fetch from external resources. It saves downstreams users a lot of pain.
This is an impressive walkthrough and library you have wrote. One question I had: did you use wasm to generate typescript bindings for napi-rs? I was trying to find best way to do it and only stumbled over bug: -bindings/neon/issues/349.Using your code examples:
If you see a message saying that your platform is not supported (or that Nx cannot find a @nx/nx-platform module for versions of Nx between 15.8 and 16.4), there are a few reasons why this could potentially happen:
If you are still experiencing issues after following the previous steps, please open an issue on GitHub and we will help you troubleshoot. Be prepared to give as much detail as possible about your system, we will need the following information at a minimum, the contents of nx report plus
If you're running a machine that isn't part of the list above, then Nx does not support it at this time. Please open an issue on GitHub if you feel Nx should support that platform and we will assess what can be done, please make sure to include your platform and architecture in the issue.
Ensure that the architecture of your Node.js installation matches your hardware. Run nx report and check that the OS property is correct (e.g. darwin-arm64 for MacOS on Apple silicon). If it contains x64 even though you're on an arm64 chip, then something is wrong. A mismatch in architecture can lead to errors loading Nx's native binary.
Often, the culprit of the mismatch is a faulty installation of your toolchain: Homebrew (MacOS), Node.js or VSCode (if using Nx Console). You should reinstall your toolchain with the correct architecture. Run nx report again to validate the installation.
Just like my microcontroller article, the parts I picked range from the well-worn horses that have pulled along products for the better part of this decade, to fresh-faced ICs with intriguing capabilities that you can keep up your sleeve.
Network security is about limiting software vulnerabilities and creating a trusted execution environment (TEE) where cryptographic operations can safely take place. The classic example is using client certificates to authenticate our client device to a server. If we perform the cryptographic hashing operation in a secure environment, even an attacker who has gained total control over our normal execution environment would be unable to read our private key.
Processor vendors vigorously encourage reference design modification and reuse for customer designs. I think most professional engineers are most concerned with getting Rev A hardware that boots up than playing around with optimization, so many custom Linux boards I see are spitting images of off-the-shelf EVKs.
The standard 0.8mm-pitch BGAs that mostly make up this review have a coarse-enough pitch to allow a single trace to pass between two adjacent balls, as well as allowing a via to be placed in the middle of a 4-ball grid with enough room between adjacent vias to allow a track to go between them. This is illustrated in the image above on the left: notice that the inner-most signals on the blue (bottom) layer escape the BGA package by traveling between the vias used to escape the outer-most signals on the blue layer.
While many entry-level parts can be powered by a few discrete LDOs or DC/DC converters, some parts have stringent power-sequencing requirements. Also, to minimize power consumption, many parts recommend using dynamic voltage scaling, where the core voltage is automatically lowered when the CPU idles and lowers its clock frequency.
Back when parallel-interfaced flash memory was the only game in town, there was no need for boot ROMs: unlike SPI or MMC, these devices have address and data pins, so they are easily memory-mapped; indeed, older processors would simply start executing code straight out of parallel flash on reset.
Consequently, I recommend users skip over all the newfangled tech until it matures a bit more, and instead just spin up an old-school VMWare virtual machine and install Linux on it. In VMWare you can pass through your MicroSD card reader, debug probe, and even the device itself (which usually has a USB bootloader).
The old way of doing this was manually adding C structs to a platform_data C file for the board, but the modern way is with a Device Tree, which is a configuration file that describes every piece of hardware on the board in a weird quasi-C/JSONish syntax. Each logical piece of hardware is represented as a node that is nested under its parent bus/device; its node is adorned with any configuration parameters needed by the driver.
Rather than compiling all of these separately, BusyBox collects small, light-weight versions of these programs (plus hundreds more) into a single source tree that we can compile and link into a single binary executable. We then create symbolic links to BusyBox named after all these separate tools, then when we call them on the command line to start up, BusyBox determines how it was invoked and runs the appropriate command. Genius!
Even more importantly, these build systems contain default configurations for the vendor- and community-developed dev boards that we use to test out these CPUs and base our hardware from. These default configurations are a real life-saver.
Yes, on their own, both U-Boot and Linux have defconfigs that do the heavy lifting: For example, by using a U-Boot defconfig, someone has already done the work for you in configuring U-Boot to initialize a specific boot media and boot off it (including setting up the SPL code, activating the activating the appropriate peripherals, and writing a reasonable U-Boot environment and boot script).
The Microchip, NXP, ST, and TI parts are what I would consider general-purpose MPUs: designed to drop into a wide variety of industrial and consumer connectivity, control, and graphical applications. They have 10/100 ethernet MACs (obviously requiring external PHYs to use), a parallel RGB LCD interface, a parallel camera sensor interface, two SDIO interfaces (typically one used for storage and the other for WiFi), and up to a dozen each of UARTs, SPI, I2C, and I2S interfaces. They often have extensive timers and a dozen or so ADC channels. These parts are also packaged in large BGAs that ball-out 100 or more I/O pins that enable you to build larger, more complicated systems.
The Nuvoton NUC980 is a new 300 MHz ARM9-based SIP with 64 or 128 MB of SDRAM memory built-in. The entry-level chip in this family is $4.80 in quantities of 100, making it one of the cheapest SIPs available. Plus, Nuvoton does 90% discounts on the first five pieces you buy when purchased through TechDesign, so you can get a set of chips for your prototype for a couple of bucks.
3a8082e126