neon-bindings / neon

Rust bindings for writing safe and fast native Node.js modules.
https://www.neon-bindings.com/
Apache License 2.0
7.98k stars 282 forks source link

feat(neon): Extractors #1024

Closed kjvalencik closed 5 months ago

kjvalencik commented 5 months ago

Extractors allow quickly getting JavaScript arguments as Rust values. In addition to immediate ergonomics and performance improvements, extractors set a foundation for future proc macros.

The Neon API surface area increases by two traits:

TryFromJs

The TryFromJs trait provides a standardized way of extracting a Rust value from a JsValue. It is initially Sealed while we determine if changes are needed. In a future release, we will likely make it available for users to implement.

FromArgs

The FromArgs trait is an implementation detail and will remain Sealed. It is implemented by a macro for tuples up to size 32.

Extractors

TryFromJs is implemented for many standard library values (f64, String) and wrapper types (Option). It also has blanket implementations for Handle and NeonResult. Additionally, I introduce the concept of an "extractor". The idea is inspired by axum. These extractors allow for specialization where extracted types would otherwise overlap. For example, getting an f64 from a Date.

Most extractors are implemented using the sys crate directly in order to avoid duplicate type checks. In the future, we will likely want to convert existing functions to use the TryFromJs implementations.

Json

As found previously, serialization to JSON is nearly always faster than manually reading JavaScript objects. Working with JSON, thanks to serde, is also much easier. Community crates like neon-serde have demonstrated a high demand for this functionality.

The Json extractor leverages serde and serde_json to convert to a Rust type. The ✨ magic ✨ is that it doesn't require the value to already be stringified on the JavaScript side. It leverage's Neon's new LocalKey functionality for fast access to JSON.stringify. JSON.stringify and serde_json::from_str are implicitly called when extracting.