From c6258cf6338a7b4e365f8a718989d12d46104e70 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Fri, 26 May 2023 18:28:34 +0800 Subject: [PATCH] feat(napi): support chrono::NaiveDateTime (#1601) --- crates/backend/src/typegen.rs | 1 + .../src/bindgen_runtime/js_values/date.rs | 93 +++++++++++++++++- .../__snapshots__/typegen.spec.ts.md | 4 + .../__snapshots__/typegen.spec.ts.snap | Bin 3987 -> 4015 bytes examples/napi/__tests__/values.spec.ts | 13 +++ examples/napi/index.d.ts | 4 + examples/napi/src/date.rs | 12 +++ 7 files changed, 126 insertions(+), 1 deletion(-) diff --git a/crates/backend/src/typegen.rs b/crates/backend/src/typegen.rs index 11c1d819..c9d4de08 100644 --- a/crates/backend/src/typegen.rs +++ b/crates/backend/src/typegen.rs @@ -161,6 +161,7 @@ static KNOWN_TYPES: Lazy> = La ("BigUint64Array", ("BigUint64Array", false, false)), ("DataView", ("DataView", false, false)), ("DateTime", ("Date", false, false)), + ("NaiveDateTime", ("Date", false ,false)), ("Date", ("Date", false, false)), ("JsDate", ("Date", false, false)), ("JsBuffer", ("Buffer", false, false)), diff --git a/crates/napi/src/bindgen_runtime/js_values/date.rs b/crates/napi/src/bindgen_runtime/js_values/date.rs index 0f622ec4..6ed32266 100644 --- a/crates/napi/src/bindgen_runtime/js_values/date.rs +++ b/crates/napi/src/bindgen_runtime/js_values/date.rs @@ -1,4 +1,4 @@ -use std::ptr; +use std::{ptr, str::FromStr}; use chrono::{DateTime, NaiveDateTime, Utc}; @@ -29,6 +29,97 @@ impl ValidateNapiValue for DateTime { } } +impl ToNapiValue for NaiveDateTime { + unsafe fn to_napi_value(env: sys::napi_env, val: NaiveDateTime) -> Result { + let mut ptr = std::ptr::null_mut(); + let millis_since_epoch_utc = val.timestamp_millis() as f64; + + check_status!( + unsafe { sys::napi_create_date(env, millis_since_epoch_utc, &mut ptr) }, + "Failed to convert rust type `NaiveDateTime` into napi value", + )?; + + Ok(ptr) + } +} + +impl FromNapiValue for NaiveDateTime { + unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { + let mut to_iso_string = ptr::null_mut(); + check_status!( + unsafe { + napi_sys::napi_create_string_utf8( + env, + "toISOString\0".as_ptr().cast(), + 11, + &mut to_iso_string, + ) + }, + "create toISOString JavaScript string failed" + )?; + let mut to_iso_string_method = ptr::null_mut(); + check_status!( + unsafe { sys::napi_get_property(env, napi_val, to_iso_string, &mut to_iso_string_method) }, + "get toISOString method failed" + )?; + let mut iso_string_value = ptr::null_mut(); + check_status!( + unsafe { + sys::napi_call_function( + env, + napi_val, + to_iso_string_method, + 0, + ptr::null(), + &mut iso_string_value, + ) + }, + "Call toISOString on Date Object failed" + )?; + + let mut iso_string_length = 0; + check_status!( + unsafe { + sys::napi_get_value_string_utf8( + env, + iso_string_value, + ptr::null_mut(), + 0, + &mut iso_string_length, + ) + }, + "Get ISOString length failed" + )?; + let mut iso_string = String::with_capacity(iso_string_length + 1); + check_status!( + unsafe { + sys::napi_get_value_string_utf8( + env, + iso_string_value, + iso_string.as_mut_ptr().cast(), + iso_string_length, + &mut iso_string_length, + ) + }, + "Get ISOString length failed" + )?; + + unsafe { iso_string.as_mut_vec().set_len(iso_string_length) }; + + let naive = NaiveDateTime::from_str(iso_string.as_str()).map_err(|err| { + Error::new( + Status::InvalidArg, + format!( + "Failed to convert napi value into rust type `NaiveDateTime` {} {}", + err, iso_string + ), + ) + })?; + + Ok(naive) + } +} + impl ToNapiValue for DateTime { unsafe fn to_napi_value(env: sys::napi_env, val: DateTime) -> Result { let mut ptr = std::ptr::null_mut(); diff --git a/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md b/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md index 2d7ed1a8..1cad4f57 100644 --- a/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md +++ b/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md @@ -268,6 +268,10 @@ Generated by [AVA](https://avajs.dev). ␊ export function chronoDateToMillis(input: Date): number␊ ␊ + export function chronoNativeDateTime(date: Date): number␊ + ␊ + export function chronoNativeDateTimeReturn(): Date | null␊ + ␊ export function concatLatin1(s: string): string␊ ␊ export function concatStr(s: string): string␊ diff --git a/examples/napi/__tests__/__snapshots__/typegen.spec.ts.snap b/examples/napi/__tests__/__snapshots__/typegen.spec.ts.snap index 910b4e9578771a37d0a117b528bce26498606f90..65b9a97356019a95857ef8256665995c245b17b4 100644 GIT binary patch literal 4015 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 V{~Uhz;C{#C{SOnZZqo!j007h<+1~&F literal 3987 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 diff --git a/examples/napi/__tests__/values.spec.ts b/examples/napi/__tests__/values.spec.ts index 4d15cb67..19e112eb 100644 --- a/examples/napi/__tests__/values.spec.ts +++ b/examples/napi/__tests__/values.spec.ts @@ -130,6 +130,8 @@ import { tsfnReturnPromise, tsfnReturnPromiseTimeout, returnFromSharedCrate, + chronoNativeDateTime, + chronoNativeDateTimeReturn, } from '../' test('export const', (t) => { @@ -980,3 +982,14 @@ Napi5Test('Class with getter setter closures', (t) => { // @ts-expect-error t.is(instance.age, 0.3) }) + +Napi5Test('Date to chrono::NativeDateTime test', (t) => { + const fixture = new Date() + t.is(chronoNativeDateTime(fixture), fixture.valueOf()) +}) + +Napi5Test('Date from chrono::NativeDateTime test', (t) => { + const fixture = chronoNativeDateTimeReturn() + t.true(fixture instanceof Date) + t.is(fixture?.toISOString(), '2016-12-23T15:25:59.325Z') +}) diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 63f523ab..aedd504f 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -258,6 +258,10 @@ export function chronoDateAdd1Minute(input: Date): Date export function chronoDateToMillis(input: Date): number +export function chronoNativeDateTime(date: Date): number + +export function chronoNativeDateTimeReturn(): Date | null + export function concatLatin1(s: string): string export function concatStr(s: string): string diff --git a/examples/napi/src/date.rs b/examples/napi/src/date.rs index f13ee76a..584e6d15 100644 --- a/examples/napi/src/date.rs +++ b/examples/napi/src/date.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use chrono::{Duration, Utc}; use napi::bindgen_prelude::*; @@ -21,3 +23,13 @@ pub struct Dates { pub start: chrono::DateTime, pub end: Option>, } + +#[napi] +pub fn chrono_native_date_time(date: chrono::NaiveDateTime) -> i64 { + date.timestamp_millis() +} + +#[napi] +pub fn chrono_native_date_time_return() -> Option { + chrono::NaiveDateTime::from_str("2016-12-23T15:25:59.325").ok() +}