@@ -55,20 +55,65 @@ internal open class {{ ffi_struct.name()|ffi_struct_name }}(
55
55
{%- endmatch % }
56
56
{%- endfor % }
57
57
58
+
59
+ {%- macro decl_kotlin_functions(func_list) -% }
60
+ {% for func in func_list -% }
61
+ fun {{ func.name () }}(
62
+ {%- call kt::arg_list_ffi_decl(func) % }
63
+ ): {% match func.return_type() % }{% when Some with (return_type) % }{{ return_type.borrow()|ffi_type_name_by_value }}{% when None % }Unit {% endmatch % }
64
+ {% endfor % }
65
+ {%- endmacro % }
66
+
67
+ // For large crates we prevent `MethodTooLargeException` (see #2340)
68
+ // N.B. the name of the extension is very misleading, since it is
69
+ // rather `InterfaceTooLargeException`, caused by too many methods
70
+ // in the interface for large crates.
71
+ //
72
+ // By splitting the otherwise huge interface into two parts
73
+ // * UniffiLib
74
+ // * UniffiLibChecksums (this)
75
+ // And all checksum methods are put into `UniffiLibChecksums`
76
+ // we allow for ~2x as many methods in the UniffiLib interface.
77
+ internal interface UniffiLibChecksums : Library {
78
+ {%- call decl_kotlin_functions(ci.iter_checksum_ffi_functions()) % }
79
+ }
80
+
58
81
// A JNA Library to expose the extern-C FFI definitions.
59
82
// This is an implementation detail which will be called internally by the public API.
60
-
61
83
internal interface UniffiLib : Library {
62
84
companion object {
63
85
internal val INSTANCE : UniffiLib by lazy {
64
- loadIndirect<UniffiLib >(componentName = " {{ ci.namespace() }}" )
65
- .also { lib: UniffiLib ->
66
- uniffiCheckContractApiVersion(lib)
67
- uniffiCheckApiChecksums(lib)
68
- {% for fn in self.initialization_fns() -% }
69
- {{ fn }}(lib)
70
- {% endfor -% }
71
- }
86
+ val componentName = " {{ ci.namespace() }}"
87
+ // For large crates we prevent `MethodTooLargeException` (see #2340)
88
+ // N.B. the name of the extension is very misleading, since it is
89
+ // rather `InterfaceTooLargeException`, caused by too many methods
90
+ // in the interface for large crates.
91
+ //
92
+ // By splitting the otherwise huge interface into two parts
93
+ // * UniffiLib (this)
94
+ // * UniffiLibChecksums
95
+ // And all checksum methods are put into `UniffiLibChecksums`
96
+ // we allow for ~2x as many methods in the UniffiLib interface.
97
+ //
98
+ // Thus we first load the library with `loadIndirect` as `UniffiLibChecksums`
99
+ // so that we can call `uniffiCheckApiChecksums`...
100
+ loadIndirect<UniffiLibChecksums >(componentName)
101
+ .also { lib: UniffiLibChecksums ->
102
+ uniffiCheckApiChecksums(lib)
103
+ }
104
+ // ... and then we load the library as `UniffiLib`
105
+ // N.B. we cannot use `loadIndirect` once and then try to cast it to `UniffiLib`
106
+ // => results in `java.lang.ClassCastException: com.sun.proxy.$Proxy cannot be cast to ...`
107
+ // error. So we must call `loadIndirect` twice. For crates large enough
108
+ // to trigger this issue, the performance impact is negligible, running on
109
+ // a macOS M1 machine the `loadIndirect` call takes ~50ms.
110
+ loadIndirect<UniffiLib >(componentName)
111
+ .also { lib: UniffiLib ->
112
+ uniffiCheckContractApiVersion(lib)
113
+ {% for fn in self.initialization_fns() -% }
114
+ {{ fn }}(lib)
115
+ {% endfor -% }
116
+ }
72
117
}
73
118
{% if ci.contains_object_types() % }
74
119
// The Cleaner for the whole library
@@ -77,12 +122,7 @@ internal interface UniffiLib : Library {
77
122
}
78
123
{%- endif % }
79
124
}
80
-
81
- {% for func in ci.iter_ffi_function_definitions() -% }
82
- fun {{ func.name () }}(
83
- {%- call kt : :arg_list_ffi_decl(func) %}
84
- ): {% match func.return_type() % }{% when Some with (return_type) % }{{ return_type.borrow()|ffi_type_name_by_value }}{% when None % }Unit{% endmatch % }
85
- {% endfor % }
125
+ {%- call decl_kotlin_functions(ci.iter_ffi_function_definitions_excluding_checksums()) % }
86
126
}
87
127
88
128
private fun uniffiCheckContractApiVersion (lib : UniffiLib ) {
@@ -96,7 +136,7 @@ private fun uniffiCheckContractApiVersion(lib: UniffiLib) {
96
136
}
97
137
98
138
@Suppress(" UNUSED_PARAMETER" )
99
- private fun uniffiCheckApiChecksums (lib : UniffiLib ) {
139
+ private fun uniffiCheckApiChecksums (lib : UniffiLibChecksums ) {
100
140
{%- for (name, expected_checksum) in ci.iter_checksums() % }
101
141
if (lib.{{ name }}() != {{ expected_checksum }}.toShort()) {
102
142
throw RuntimeException (" UniFFI API checksum mismatch: try cleaning and rebuilding your project" )
0 commit comments