From e79eb34118a1f77fd9266974115f28ad1ea23862 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Tue, 24 Jan 2023 14:25:05 +0800 Subject: [PATCH] feat(napi-derive): generate ThreadsafeFunction types (#1449) --- crates/backend/src/typegen.rs | 20 ++++++++++++---- examples/napi/__test__/typegen.spec.ts.md | 2 ++ examples/napi/__test__/typegen.spec.ts.snap | Bin 3657 -> 3690 bytes examples/napi/__test__/values.spec.ts | 24 ++++++++++++++++++++ examples/napi/index.d.ts | 2 ++ examples/napi/src/threadsafe_function.rs | 14 ++++++++++++ 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/crates/backend/src/typegen.rs b/crates/backend/src/typegen.rs index 1e94f9a2..f7eeb174 100644 --- a/crates/backend/src/typegen.rs +++ b/crates/backend/src/typegen.rs @@ -180,6 +180,7 @@ static KNOWN_TYPES: Lazy> = La ("Either25", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)), ("Either26", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)), ("external", ("object", false, false)), + ("Promise", ("Promise<{}>", false, false)), ("AbortSignal", ("AbortSignal", false, false)), ("JsGlobal", ("typeof global", false, false)), ("External", ("ExternalObject<{}>", false, false)), @@ -333,11 +334,20 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S .with(|c| c.borrow_mut().get(rust_ty.as_str()).cloned()) { ts_ty = Some((t, false)); - } else if rust_ty == "Promise" { - ts_ty = Some(( - format!("Promise<{}>", args.first().map(|(arg, _)| arg).unwrap()), - false, - )); + } else if rust_ty == "ThreadsafeFunction" { + let fatal_tsfn = match args.get(1) { + Some((arg, _)) => arg == "Fatal", + _ => false, + }; + let first_arg = args.first().map(|(arg, _)| arg).unwrap(); + ts_ty = if fatal_tsfn { + Some((format!("(value: {}) => any", first_arg), false)) + } else { + Some(( + format!("(err: Error | null, value: {}) => any", first_arg), + false, + )) + }; } else { // there should be runtime registered type in else let type_alias = ALIAS.with(|aliases| { diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index 76385fc9..7e9a0429 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -200,6 +200,8 @@ Generated by [AVA](https://avajs.dev). export function threadsafeFunctionClosureCapture(func: (...args: any[]) => any): void␊ export function tsfnCallWithCallback(func: (...args: any[]) => any): void␊ export function tsfnAsyncCall(func: (...args: any[]) => any): Promise␊ + export function acceptThreadsafeFunction(func: (err: Error | null, value: number) => any): void␊ + export function acceptThreadsafeFunctionFatal(func: (value: number) => any): void␊ export function getBuffer(): Buffer␊ export function appendBuffer(buf: Buffer): Buffer␊ export function getEmptyBuffer(): Buffer␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index 375b4dee2ebcc942c9b675e21db4fd4336c118c1..fc83e0b5ab0f3794d78fe5fca70ebc8edfbb84cb 100644 GIT binary patch literal 3690 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 Iv3E590CDadq5uE@ literal 3657 zcmV-P4z}?@RzVjW z#h<>we}4DJFaG@d^PR8m5hY`usD8vH9mkB^`|1vKGTnLK>BL@|D{CFxlo&;=!ycker)n1oGh!{Wa!c-)l(P@#cbBw>(J zHG^%?qJf#OGco6qJ=x7ClP*pvPCCkC#YdMSpxM+e=FIg;Y0Rgfc!MYkXuoJ|kg@&j z*^kz|5GYn`mroB96|4t#_-JPdr0E6~c=KpyAkQ@K!I(Rg7j{pJww5E#`fA$kEh7AI(&F8jBeuQHPCWI$& z#D9dHi{mxdI8!uJzEwKVnuTx4h+bp~H!IiCt*y_%?g?0}CKb0ri#7%`HhK(kRckeY0_-dcOg1}Ra!y1Fpv%o?eCTXq!pT;l(k}8-D;;_fEtm4jW zGRO;T4tNQdgF1>1dQud$Ms%1A3;aPi-n29z9$0z2RhOwxN^pQ#HlZOS#`7I;7Dq#L ziHG2oXaWQ1_r^Sn`eYaW26xtNq|E%cT+Q@!jR-~U!`rb>A>$X_c#JdgBkL8!HF2hK zE>98`DDb|0@|H(x=67BYa>^*B?fVcu!#py4-$c2>*KHX-QaF+zL#jvwqOWxl3GjLL1Ag(+gdQtIxrEU z-`e~NXxEr5nk@qw7C@icKwb1|yHoN$04jIk&(I%MnYp{5XD3fJ2_o$pwvbFab2fBq~v0It1hu+gs9D1Tq0?$-`E9q36EjNu=3Eth+Qj*BJsK zdtwTn`{710@)9hW)F!_eA5sP5n|6FerCJm-^Y9!)fJ%7Ia{KcX;BdVn2l`IrFpi1f z7+l6V0SN)sECr4u*whSuNy08m#&T)cebCL$FqcYTlCqC2Tn9|OB@{w=9h>0iEMwTe zjg145XYjp)-)H;^J|E%dKA+Bz$;a3@<{Ho6^<;)I&gR1|^?+qZ;&6K_VEsBVOA;io z{FmAz2flbEr3nwcqsH0VbTyFt6LZdDBaQWCEp;SCvVc+t1L7o34Qw{o>Rw3FzP5B3om&|v{3lxZ>W7i2RL`2!zxvZUO(#8OiI`g%9#%PhU$Shc# z_%~p99_yYp*3)TKX)9JFlI1L8Qv%+1oN4jporD2H5Uq+-(p6!o43~oi=#B2 z;n>Ewt6~*9^&2W@M>MsfJY}KCq9-=3TAPAn2-i`rI@?$+)Hl|B;hfT!tufI?W-Z_9 zol#^8LE0)*tWmnKNQ&bxorCZ3Y2^%E;Lr$!cK8g%z0kmuw+1 zd$)VoDqMSu3CnB9U&mrhwGi+MK}^V0cXWZS7KN@!w?*ot9dT?8m~me^+N`NIwCR*R zUy@A}nOX}MiU;Pk*XYy_mjNdh9=tjnoN1~CHk9ARxV0Gc%w$WbVTD;@rB2qn?anh^=Q zu^NzqvA};G^(DvaIG39bAFdZK)NZX3M?#pXrC{qp-ydL^*U8Q*pw|ZA1&+6NxyU0S z{j+6cIKh|=7HCa!S&TWeB9<~Z5=qFJeBQFdkT*ZmKo@(f;kp!!Mh?{|OQ+c-cxU(+ zeR^88YjgenRWYf~uwH&D;H(2o8sNpJt_Jk_-6d&A(biyB5v(j z_!ihDoJ^6c!5DgnAm>cPF`Pe-n_LxOBer!=Z4k+)I@Q(CXS%TlevG-Wwm~CFCr+MJ zg<_uKlE+4>7OqiMthh<#>spOM62EM%Usp}A<$_dK`9Dku7GMu*4t zj^$NOjDFHdNxpQdx;bcr>%J86DOkf%)sIg*7;VV2Fm~jUA@`f zYE?#xu9Z&`>SZgZ%F?Uh@syU@RhffWP-pSZ9f(-QCRO_c(2 ztV4niruPFl(jRh;x51#ZkTkG3l0*qI2KSziV;*iG8hr_I3HZTpO$nc;0E#pb2R*|5 z^&MV02TpJA{T;U+te@`;5DJLi`EchP2KySMj6+P2g8_)Mj+y3k z1l7!qT0GNhAfg09AegWqa|RA2GMFSNArG}zKokx(RD4Y-Kw;RY3j{qU?vb{$xhg_q z9E#8dN78mV_zivdK*=G}H0Sv4<$jD6?@-L=EK#N($;7aa&BaGf{`cSi{7d&EBbPHl z=e$Os%e~5UH(kl@g6T}HPzz2^P8(QLe%>4=|QwX7>eV?N@%9RjUY zLx{_ilTPSP406p2E5|(8M7~^Czvj zU6Y2`G2~-cCc&N4#h4v47F88ZOtkg#uHA0zO0Ul09uQqnUIxjVSbP@Xjwm>_lnwe*uH`?_X;6DPfnVG@YSL96F5NA5nQe6tOw?B|XJ~ zsP!4^ftIj%a)N*N%uhqbUdVxz_+s-ZF&~XBFoV|}N&yQ8JaQ6|0+lTqcCKTW=~%_L zh<=p&nyQ&&2O3*u>mKfLtRC%sZr%!S z#nJK?dcNiLo4nfzrFm$CdYf^D&z`lvx~;93g%;QPn>MkqY1$1Qa3Ga`VlAz?#Mf0- zPCH|GrS3iK`Yo1u(PPeVr}e0fwQ!UU`k)B6{8j@EV;7%I6n=@+kFX)2^?0Ryl3JFv z)C#sjXhCT**k7t+ zm!s9Td3bhqn#b%FmuR1dQrcES&#M8A6KpfKJN`ESW4BX^vN}_Xn4QfS({UUuRdsac z8Qt!qHqQ|0;AxWSfHuWg4+Ju#zd^lqJDKIp6$pV;z#JWS6)k~|{st2kq`^z)%+BN5 z;>=5DxiIo8Q!IsFUCoTf*RE{_uMWRHKH5JXIU3(_!MXj zIxyj@{iTS$MLG@NE)LW4t!1JeDwx?Owl*`%NV~b7b}Kj@@hQapflI=TM|NAT>|BPn b@H%6~9cH&ozg>B8d~@gjMuw&`#WVl_!Or<{ diff --git a/examples/napi/__test__/values.spec.ts b/examples/napi/__test__/values.spec.ts index 1747067c..87ad5b3b 100644 --- a/examples/napi/__test__/values.spec.ts +++ b/examples/napi/__test__/values.spec.ts @@ -116,6 +116,8 @@ import { captureErrorInCallback, bigintFromI128, bigintFromI64, + acceptThreadsafeFunction, + acceptThreadsafeFunctionFatal, } from '../' test('export const', (t) => { @@ -792,6 +794,28 @@ Napi4Test('async call ThreadsafeFunction', async (t) => { ) }) +Napi4Test('accept ThreadsafeFunction', async (t) => { + await new Promise((resolve, reject) => { + acceptThreadsafeFunction((err, value) => { + if (err) { + reject(err) + } else { + t.is(value, 1) + resolve() + } + }) + }) +}) + +Napi4Test('accept ThreadsafeFunction Fatal', async (t) => { + await new Promise((resolve) => { + acceptThreadsafeFunctionFatal((value) => { + t.is(value, 1) + resolve() + }) + }) +}) + const Napi5Test = Number(process.versions.napi) >= 5 ? test : test.skip Napi5Test('Date test', (t) => { diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index aab94c85..df0dcced 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -190,6 +190,8 @@ export function threadsafeFunctionFatalModeError(cb: (...args: any[]) => any): v export function threadsafeFunctionClosureCapture(func: (...args: any[]) => any): void export function tsfnCallWithCallback(func: (...args: any[]) => any): void export function tsfnAsyncCall(func: (...args: any[]) => any): Promise +export function acceptThreadsafeFunction(func: (err: Error | null, value: number) => any): void +export function acceptThreadsafeFunctionFatal(func: (value: number) => any): void export function getBuffer(): Buffer export function appendBuffer(buf: Buffer): Buffer export function getEmptyBuffer(): Buffer diff --git a/examples/napi/src/threadsafe_function.rs b/examples/napi/src/threadsafe_function.rs index fc762e88..fe88ab64 100644 --- a/examples/napi/src/threadsafe_function.rs +++ b/examples/napi/src/threadsafe_function.rs @@ -102,3 +102,17 @@ pub fn tsfn_async_call(env: Env, func: JsFunction) -> napi::Result { Ok(()) }) } + +#[napi] +pub fn accept_threadsafe_function(func: ThreadsafeFunction) { + thread::spawn(move || { + func.call(Ok(1), ThreadsafeFunctionCallMode::NonBlocking); + }); +} + +#[napi] +pub fn accept_threadsafe_function_fatal(func: ThreadsafeFunction) { + thread::spawn(move || { + func.call(1, ThreadsafeFunctionCallMode::NonBlocking); + }); +}