1#[macro_export]
43macro_rules! split_by_comma {
44 (
47 {$($input:tt)*},
48 $macro:path $(,$args:tt)*
49 ) => {
50 $crate::split_by_comma! {
51 {$($input)*},
52 {}, {}, $macro $(,$args)*
55 }
56 };
57 (
61 {
62 ,
63 $($rest:tt)*
64 },
65 {
66 $(
67 {$($prev_split:tt)*}
68 )*
69 },
70 {
71 $($current_split:tt)*
72 },
73 $macro:path $(,$args:tt)*
74 ) => {
75 $crate::split_by_comma! {
76 {
77 $($rest)*
78 },
79 {
80 $(
81 {$($prev_split)*}
82 )*
83 {
84 $($current_split)*
85 }
86 },
87 {},
88 $macro $(,$args)*
89 }
90 };
91 (
94 {},
95 {
96 $(
97 {$($prev_split:tt)*}
98 )*
99 },
100 {
101 $($current_split:tt)+
102 },
103 $macro:path $(,$args:tt)*
104 ) => {
105 $crate::split_by_comma! {
106 {},
107 {
108 $(
109 {$($prev_split)*}
110 )*
111 {
112 $($current_split)+
113 }
114 },
115 {},
116 $macro $(,$args)*
117 }
118 };
119 (
121 {
122 $first:tt
123 $($rest:tt)*
124 },
125 {
126 $(
127 {$($prev_split:tt)*}
128 )*
129 },
130 {
131 $($current_split:tt)*
132 },
133 $macro:path $(,$args:tt)*
134 ) => {
135 $crate::split_by_comma! {
136 {
137 $($rest)*
138 },
139 {
140 $(
141 {$($prev_split)*}
142 )*
143 },
144 {
145 $($current_split)* $first
146 },
147 $macro $(,$args)*
148 }
149 };
150 (
152 {},
153 {
154 $(
155 {$($prev_split:tt)*}
156 )*
157 },
158 {},
159 $macro:path $(,$args:tt)*
160 ) => {
161 $macro! {
162 {
163 $(
164 {$($prev_split)*}
165 )*
166 }
167 $(,$args)*
168 }
169 };
170}
171#[macro_export]
186macro_rules! gen_class_name {
187 ($single_part_class:ident $($param_name:ident)?) => {
189 $crate::gen_class_name! { @inner java.lang.$single_part_class }
190 };
191 ($($class:ident).+ $($param_name:ident)?) => {
192 $crate::gen_class_name! { @inner $($class).+ }
193 };
194 (@inner $last:ident) => {
195 stringify! {$last}
196 };
197 (@inner $first:ident . $($rest:ident).+) => {
198 concat! {stringify! {$first}, "/", $crate::gen_class_name! {@inner $($rest).+} }
199 }
200}
201
202#[macro_export]
219macro_rules! gen_jni_type_sig {
220 (boolean $($param_name:ident)?) => {
221 "Z"
222 };
223 (byte $($param_name:ident)?) => {
224 "B"
225 };
226 (char $($param_name:ident)?) => {
227 "C"
228 };
229 (short $($param_name:ident)?) => {
230 "S"
231 };
232 (int $($param_name:ident)?) => {
233 "I"
234 };
235 (long $($param_name:ident)?) => {
236 "J"
237 };
238 (float $($param_name:ident)?) => {
239 "F"
240 };
241 (double $($param_name:ident)?) => {
242 "D"
243 };
244 (void) => {
245 "V"
246 };
247 (Class $(< ? >)? $($param_name:ident)?) => {
248 $crate::gen_jni_type_sig! { java.lang.Class }
249 };
250 ($($class_part:ident).+ $($param_name:ident)?) => {
251 concat! {"L", $crate::gen_class_name! {$($class_part).+}, ";"}
252 };
253 ($($class_part:ident).+ [] $($param_name:ident)?) => {
254 concat! { "[", $crate::gen_jni_type_sig! {$($class_part).+}}
255 };
256 ($($invalid:tt)*) => {
257 compile_error!(concat!("unsupported type `", stringify!($($invalid)*), "`"))
258 };
259}
260
261#[macro_export]
281macro_rules! cast_jvalue {
282 ({ boolean }, $value:expr) => {{ $value.z().expect("should be bool") }};
283 ({ byte }, $value:expr) => {{ $value.b().expect("should be byte") }};
284 ({ char }, $value:expr) => {{ $value.c().expect("should be char") }};
285 ({ double }, $value:expr) => {{ $value.d().expect("should be double") }};
286 ({ float }, $value:expr) => {{ $value.f().expect("should be float") }};
287 ({ int }, $value:expr) => {{ $value.i().expect("should be int") }};
288 ({ long }, $value:expr) => {{ $value.j().expect("should be long") }};
289 ({ short }, $value:expr) => {{ $value.s().expect("should be short") }};
290 ({ void }, $value:expr) => {{ $value.v().expect("should be void") }};
291 ({ byte[] }, $value:expr) => {{
292 let obj = $value.l().expect("should be object");
293 unsafe { jni::objects::JByteArray::from_raw(obj.into_raw()) }
294 }};
295 ({ $($class:tt)+ }, $value:expr) => {{ $value.l().expect("should be object") }};
296}
297
298#[macro_export]
321macro_rules! to_jvalue {
322 ({ boolean $($param_name:ident)? }, $value:expr) => {{ jni::objects::JValue::Bool($value as _) }};
323 ({ byte $($param_name:ident)? }, $value:expr) => {{ jni::objects::JValue::Byte($value as _) }};
324 ({ char $($param_name:ident)? }, $value:expr) => {{ jni::objects::JValue::Char($value as _) }};
325 ({ double $($param_name:ident)? }, $value:expr) => {{ jni::objects::JValue::Double($value as _) }};
326 ({ float $($param_name:ident)? }, $value:expr) => {{ jni::objects::JValue::Float($value as _) }};
327 ({ int $($param_name:ident)? }, $value:expr) => {{ jni::objects::JValue::Int($value as _) }};
328 ({ long $($param_name:ident)? }, $value:expr) => {{ jni::objects::JValue::Long($value as _) }};
329 ({ short $($param_name:ident)? }, $value:expr) => {{ jni::objects::JValue::Short($value as _) }};
330 ({ void }, $value:expr) => {{
331 compile_error! {concat! {"unlike to pass void value: ", stringify! {$value} }}
332 }};
333 ({ $($class:ident)+ $([])? $($param_name:ident)? }, $value:expr) => {{ jni::objects::JValue::Object($value as _) }};
334}
335
336#[macro_export]
373macro_rules! gen_jni_sig {
374 ({$({$($args:tt)+})*}, {return {$($ret:tt)*}}) => {{
376 concat! {
377 "(", $($crate::gen_jni_type_sig!{ $($args)+ },)* ")",
378 $crate::gen_jni_type_sig! {$($ret)+}
379 }
380 }};
381 ({$($ret:tt)*}, {$($args:tt)*}) => {{
382 $crate::split_by_comma! {
383 {$($args)*},
384 $crate::gen_jni_sig,
385 {return {$($ret)*}}
386 }
387 }};
388 ({{$func_name:ident, {$($ret:tt)*}, {$($args:tt)*}}}) => {{
390 $crate::gen_jni_sig! {
391 {$($ret)*}, {$($args)*}
392 }
393 }};
394 ($($input:tt)*) => {{
395 $crate::split_extract_plain_native_methods! {{$($input)*;}, $crate::gen_jni_sig}
396 }}
397}
398
399#[macro_export]
400macro_rules! for_all_plain_native_methods {
401 ($macro:path $(,$args:tt)*) => {
402 $macro! {
403 {
404 public static native void tracingSlf4jEvent(String threadName, String name, int level, String message, String stackTrace);
405
406 public static native boolean tracingSlf4jEventEnabled(int level);
407
408 public static native int defaultVnodeCount();
409
410 static native long iteratorNewStreamChunk(long pointer);
411
412 static native boolean iteratorNext(long pointer);
413
414 static native void iteratorClose(long pointer);
415
416 static native long newStreamChunkFromPayload(byte[] streamChunkPayload);
417
418 static native long newStreamChunkFromPretty(String str);
419
420 static native void streamChunkClose(long pointer);
421
422 static native byte[] iteratorGetKey(long pointer);
423
424 static native int iteratorGetOp(long pointer);
425
426 static native boolean iteratorIsNull(long pointer, int index);
427
428 static native short iteratorGetInt16Value(long pointer, int index);
429
430 static native int iteratorGetInt32Value(long pointer, int index);
431
432 static native long iteratorGetInt64Value(long pointer, int index);
433
434 static native float iteratorGetFloatValue(long pointer, int index);
435
436 static native double iteratorGetDoubleValue(long pointer, int index);
437
438 static native boolean iteratorGetBooleanValue(long pointer, int index);
439
440 static native String iteratorGetStringValue(long pointer, int index);
441
442 static native java.time.LocalDateTime iteratorGetTimestampValue(long pointer, int index);
443
444 static native java.time.OffsetDateTime iteratorGetTimestamptzValue(long pointer, int index);
445
446 static native java.math.BigDecimal iteratorGetDecimalValue(long pointer, int index);
447
448 static native java.time.LocalTime iteratorGetTimeValue(long pointer, int index);
449
450 static native java.time.LocalDate iteratorGetDateValue(long pointer, int index);
451
452 static native String iteratorGetIntervalValue(long pointer, int index);
453
454 static native String iteratorGetJsonbValue(long pointer, int index);
455
456 static native byte[] iteratorGetByteaValue(long pointer, int index);
457
458 static native Object iteratorGetArrayValue(long pointer, int index, Class<?> clazz);
460
461 public static native boolean sendCdcSourceMsgToChannel(long channelPtr, byte[] msg);
462
463 public static native boolean sendCdcSourceErrorToChannel(long channelPtr, String errorMsg);
464
465 public static native void cdcSourceSenderClose(long channelPtr);
466
467 public static native com.risingwave.java.binding.JniSinkWriterStreamRequest
468 recvSinkWriterRequestFromChannel(long channelPtr);
469
470 public static native boolean sendSinkWriterResponseToChannel(long channelPtr, byte[] msg);
471
472 public static native boolean sendSinkWriterErrorToChannel(long channelPtr, String msg);
473
474 public static native byte[] recvSinkCoordinatorRequestFromChannel(long channelPtr);
475
476 public static native boolean sendSinkCoordinatorResponseToChannel(long channelPtr, byte[] msg);
477 }
478 $(,$args)*
479 }
480 };
481}
482
483#[macro_export]
513macro_rules! split_extract_plain_native_methods {
514 (
515 {$($input:tt)*},
516 $macro:path
517 $(,$extra_args:tt)*
518 ) => {{
519 $crate::split_extract_plain_native_methods! {
520 {$($input)*},
521 {},
522 $macro
523 $(,$extra_args)*
524 }
525 }};
526 (
527 {
528 $(public)? static native $($first:tt)*
529 },
530 {
531 $($second:tt)*
532 },
533 $macro:path
534 $(,$extra_args:tt)*
535 ) => {
536 $crate::split_extract_plain_native_methods! {
537 {
538 $($first)*
539 },
540 {
541 $($second)*
542 },
543 $macro
544 $(,$extra_args)*
545 }
546 };
547 (
548 {
549 $($ret:tt).+ $func_name:ident($($args:tt)*); $($rest:tt)*
550 },
551 {
552 $({$prev_func_name:ident, {$($prev_ret:tt)*}, {$($prev_args:tt)*}})*
553 },
554 $macro:path
555 $(,$extra_args:tt)*
556 ) => {
557 $crate::split_extract_plain_native_methods! {
558 {$($rest)*},
559 {
560 $({$prev_func_name, {$($prev_ret)*}, {$($prev_args)*}})*
561 {$func_name, {$($ret).+}, {$($args)*}}
562 },
563 $macro
564 $(,$extra_args)*
565 }
566 };
567 (
568 {
569 $($ret:tt).+ [] $func_name:ident($($args:tt)*); $($rest:tt)*
570 },
571 {
572 $({$prev_func_name:ident, {$($prev_ret:tt)*}, {$($prev_args:tt)*}})*
573 },
574 $macro:path
575 $(,$extra_args:tt)*
576 ) => {
577 $crate::split_extract_plain_native_methods! {
578 {$($rest)*},
579 {
580 $({$prev_func_name, {$($prev_ret)*}, {$($prev_args)*}})*
581 {$func_name, {$($ret).+ []}, {$($args)*}}
582 },
583 $macro
584 $(,$extra_args)*
585 }
586 };
587 (
588 {},
589 {
590 $({$func_name:ident, {$($ret:tt)*}, {$($args:tt)*}})*
591 },
592 $macro:path
593 $(,$extra_args:tt)*
594 ) => {
595 $macro! {
596 {
597 $({$func_name, {$($ret)*}, {$($args)*}})*
598 }
599 $(,$extra_args)*
600 }
601 };
602 ($($invalid:tt)*) => {
603 compile_error!(concat!("unable to split extract `", stringify!($($invalid)*), "`"))
604 };
605}
606
607#[macro_export]
610macro_rules! for_all_native_methods {
611 ($macro:path $(,$args:tt)*) => {{
612 $crate::for_all_plain_native_methods! {
613 $crate::for_all_native_methods,
614 $macro
615 $(,$args)*
616 }
617 }};
618 (
619 {
620 $({$func_name:ident, {$($ret:tt)*}, {$($args:tt)*}})*
621 },
622 $macro:path
623 $(,$extra_args:tt)*
624 ) => {{
625 $macro! {
626 {$({$func_name, {$($ret)*}, {$($args)*}})*}
627 $(,$extra_args)*
628 }
629 }};
630 (
631 {$($input:tt)*},
632 $macro:path
633 $(,$extra_args:tt)*
634 ) => {{
635 $crate::split_extract_plain_native_methods! {
636 {$($input)*},
637 $crate::for_all_native_methods,
638 $macro
639 $(,$extra_args)*
640 }
641 }};
642}
643
644#[macro_export]
667macro_rules! convert_args_list {
668 (
669 {
670 {$($first_args:tt)+}
671 $({$($args:tt)+})*
672 },
673 {
674 {$first_value:expr}
675 $({$value:expr})*
676 },
677 {
678 $({$converted:expr})*
679 }) => {
680 $crate::convert_args_list! {
681 {$({$($args)+})*},
682 {$({$value})*},
683 {
684 $({$converted})*
685 {
686 $crate::to_jvalue! {
687 {$($first_args)+},
688 {$first_value}
689 }
690 }
691 }
692 }
693 };
694 ({$($args:tt)+}, {}, {$({$converted:expr})*}) => {
695 compile_error! {concat!{"trailing argument not passed: ", stringify!{$($args)+}}}
696 };
697 ({}, {$($value:tt)+}, {$({$converted:expr})*}) => {
698 compile_error! {concat!{"trailing extra value passed: ", stringify!{$($value)+}}}
699 };
700 ({}, {}, {$({$converted:expr})*}) => {
701 [$(
702 $converted
703 ),*]
704 };
705 ({$($args:tt)*}, {$($value:expr),*}) => {{
706 $crate::split_by_comma! {
707 {$($args)*},
708 $crate::convert_args_list,
709 {$({$value})*},
710 {}
711 }
712 }};
713 ($($invalid:tt)*) => {
714 compile_error!(concat!("failed to convert `", stringify!($($invalid)*), "`"))
715 };
716}
717
718#[macro_export]
719macro_rules! call_static_method {
720 (
721 {{$func_name:ident, {$($ret:tt)*}, {$($args:tt)*}}},
722 {$($class:ident).+},
723 {$env:expr} $(, $method_args:expr)*
724 ) => {{
725 $crate::call_static_method! {
726 $env,
727 $crate::gen_class_name!($($class).+),
728 stringify! {$func_name},
729 {{$($ret)*}, {$($args)*}}
730 $(, $method_args)*
731 }
732 }};
733 ($env:expr, {$($class:ident).+}, {$($method:tt)*} $(, $args:expr)*) => {{
734 $crate::split_extract_plain_native_methods! {
735 {$($method)*;},
736 $crate::call_static_method,
737 {$($class).+},
738 {$env} $(, $args)*
739 }
740 }};
741 (
742 $env:expr,
743 $class_name:expr,
744 $func_name:expr,
745 {{$($ret:tt)*}, {$($args:tt)*}}
746 $(, $method_args:expr)*
747 ) => {{
748 $env.call_static_method(
749 $class_name,
750 $func_name,
751 $crate::gen_jni_sig! { {$($ret)+}, {$($args)*}},
752 &{
753 $crate::convert_args_list! {
754 {$($args)*},
755 {$($method_args),*}
756 }
757 },
758 ).map(|jvalue| {
759 $crate::cast_jvalue! {
760 {$($ret)*},
761 jvalue
762 }
763 })
764 }};
765}
766
767#[macro_export]
768macro_rules! call_method {
769 (
770 {{$func_name:ident, {$($ret:tt)*}, {$($args:tt)*}}},
771 $env:expr, $obj:expr $(, $method_args:expr)*
772 ) => {{
773 $env.call_method(
774 $obj,
775 stringify!{$func_name},
776 $crate::gen_jni_sig! { {$($ret)+}, {$($args)*}},
777 &{
778 $crate::convert_args_list! {
779 {$($args)*},
780 {$($method_args),*}
781 }
782 },
783 ).map(|jvalue| {
784 $crate::cast_jvalue! {
785 {$($ret)*},
786 jvalue
787 }
788 })
789 }};
790 ($env:expr, $obj:expr, {$($method:tt)*} $(, $args:expr)*) => {{
791 $crate::split_extract_plain_native_methods! {
792 {$($method)*;},
793 $crate::call_method,
794 $env, $obj $(, $args)*
795 }
796 }};
797}
798
799#[macro_export]
800macro_rules! gen_native_method_entry {
801 (
802 $class_prefix:ident, $func_name:ident, {$($ret:tt)+}, {$($args:tt)*}
803 ) => {{
804 {
805 let fn_ptr = $crate::paste! {[<$class_prefix $func_name> ]} as *mut c_void;
806 let sig = $crate::gen_jni_sig! { {$($ret)+}, {$($args)*}};
807 jni::NativeMethod {
808 name: jni::strings::JNIString::from(stringify! {$func_name}),
809 sig: jni::strings::JNIString::from(sig),
810 fn_ptr,
811 }
812 }
813 }};
814}
815
816#[cfg(test)]
817mod tests {
818 use std::fmt::Formatter;
819
820 #[test]
821 fn test_for_all_gen() {
822 macro_rules! gen_array {
823 (test) => {{
824 for_all_native_methods! {
825 {
826 public static native int defaultVnodeCount();
827 static native long hummockIteratorNew(byte[] readPlan);
828 public static native byte[] rowGetKey(long pointer);
829 },
830 gen_array
831 }
832 }};
833 (all) => {{
834 for_all_native_methods! {
835 gen_array
836 }
837 }};
838 ({$({ $func_name:ident, {$($ret:tt)+}, {$($args:tt)*} })*}) => {{
839 [
840 $(
841 (stringify! {$func_name}, gen_jni_sig! { {$($ret)+}, {$($args)*}}),
842 )*
843 ]
844 }};
845 }
846 let sig: [(_, _); 3] = gen_array!(test);
847 assert_eq!(
848 sig,
849 [
850 ("defaultVnodeCount", "()I"),
851 ("hummockIteratorNew", "([B)J"),
852 ("rowGetKey", "(J)[B")
853 ]
854 );
855
856 let sig = gen_array!(all);
857 assert!(!sig.is_empty());
858 }
859
860 #[test]
861 fn test_all_native_methods() {
862 let expected = expect_test::expect![[r#"
864 [
865 tracingSlf4jEvent (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V,
866 tracingSlf4jEventEnabled (I)Z,
867 defaultVnodeCount ()I,
868 iteratorNewStreamChunk (J)J,
869 iteratorNext (J)Z,
870 iteratorClose (J)V,
871 newStreamChunkFromPayload ([B)J,
872 newStreamChunkFromPretty (Ljava/lang/String;)J,
873 streamChunkClose (J)V,
874 iteratorGetKey (J)[B,
875 iteratorGetOp (J)I,
876 iteratorIsNull (JI)Z,
877 iteratorGetInt16Value (JI)S,
878 iteratorGetInt32Value (JI)I,
879 iteratorGetInt64Value (JI)J,
880 iteratorGetFloatValue (JI)F,
881 iteratorGetDoubleValue (JI)D,
882 iteratorGetBooleanValue (JI)Z,
883 iteratorGetStringValue (JI)Ljava/lang/String;,
884 iteratorGetTimestampValue (JI)Ljava/time/LocalDateTime;,
885 iteratorGetTimestamptzValue (JI)Ljava/time/OffsetDateTime;,
886 iteratorGetDecimalValue (JI)Ljava/math/BigDecimal;,
887 iteratorGetTimeValue (JI)Ljava/time/LocalTime;,
888 iteratorGetDateValue (JI)Ljava/time/LocalDate;,
889 iteratorGetIntervalValue (JI)Ljava/lang/String;,
890 iteratorGetJsonbValue (JI)Ljava/lang/String;,
891 iteratorGetByteaValue (JI)[B,
892 iteratorGetArrayValue (JILjava/lang/Class;)Ljava/lang/Object;,
893 sendCdcSourceMsgToChannel (J[B)Z,
894 sendCdcSourceErrorToChannel (JLjava/lang/String;)Z,
895 cdcSourceSenderClose (J)V,
896 recvSinkWriterRequestFromChannel (J)Lcom/risingwave/java/binding/JniSinkWriterStreamRequest;,
897 sendSinkWriterResponseToChannel (J[B)Z,
898 sendSinkWriterErrorToChannel (JLjava/lang/String;)Z,
899 recvSinkCoordinatorRequestFromChannel (J)[B,
900 sendSinkCoordinatorResponseToChannel (J[B)Z,
901 ]
902 "#]];
903
904 struct MethodInfo {
905 name: &'static str,
906 sig: &'static str,
907 }
908
909 impl std::fmt::Debug for MethodInfo {
910 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
911 write!(f, "{:40} {}", self.name, self.sig)
912 }
913 }
914
915 macro_rules! gen_all_native_method_info {
916 () => {{
917 $crate::for_all_native_methods! {
918 gen_all_native_method_info
919 }
920 }};
921 ({$({$func_name:ident, {$($ret:tt)*}, {$($args:tt)*}})*}) => {
922 [$(
923 (
924 MethodInfo {
925 name: stringify! {$func_name},
926 sig: $crate::gen_jni_sig! {
927 {$($ret)*}, {$($args)*}
928 },
929 }
930 )
931 ),*]
932 }
933 }
934 let info = gen_all_native_method_info!();
935 expected.assert_debug_eq(&info);
936 }
937}