pub struct KtFunInterface {
pub vis: KtVis,
pub name: String,
pub type_params: Vec<String>,
pub kdoc: Option<String>,
pub method: KtFunSig,
}Expand description
A fun interface (SAM) declaration: exactly one abstract method.
The method is a KtFunSig, so it cannot carry a body; its JNI-callable
JVM name is the method’s name verbatim — keep the interface and the
method public and its params free of @JvmInline value classes, or
Kotlin mangles the JVM method name and native GetMethodID fails at
runtime.
Fields§
§vis: KtVis§name: String§type_params: Vec<String>Type parameters with variance as written, e.g. ["out R"].
kdoc: Option<String>§method: KtFunSigThe single abstract method.
Implementations§
Source§impl KtFunInterface
impl KtFunInterface
Sourcepub fn new(name: impl Into<String>, method: KtFunSig) -> Self
pub fn new(name: impl Into<String>, method: KtFunSig) -> Self
Examples found in repository?
examples/showcase.rs (lines 301-306)
164fn session_fragment() -> KtFile {
165 // `abstract class` with an `abstract` member (bodiless, and it says so),
166 // a `@Volatile` property, and an interface it implements.
167 let base = KtClass::class_with(KtClassModifier::Abstract, "NativeHandle")
168 .vis(KtVis::Public)
169 .kdoc("Owns a raw pointer into Rust and frees it exactly once.")
170 .ctor_param(KtCtorParam::new("initialPtr", KtType::long()))
171 .implements(KtType::cls("AutoCloseable"))
172 .member(
173 KtProperty::var("ptr")
174 .ty(KtType::long())
175 .vis(KtVis::Internal)
176 .annotation("Volatile")
177 .kdoc("Zero once closed.")
178 .initializer("initialPtr"),
179 )
180 .member(
181 KtProperty::val("isClosed")
182 .ty(KtType::boolean())
183 .vis(KtVis::Public)
184 .accessors(KtCode::new().line("get() = ptr == 0L")),
185 )
186 .member(
187 KtFun::new("freePtr")
188 .vis(KtVis::Public)
189 .modifier("abstract")
190 .kdoc("Release the native allocation. Called once, under the lock.")
191 .param(KtParam::new("ptr", KtType::long())),
192 );
193
194 // `open class` extending the abstract base and constructing it.
195 let session = KtClass::class_with(KtClassModifier::Open, "Session")
196 .vis(KtVis::Public)
197 .annotation("Suppress(\"unused\")")
198 .ctor_param(KtCtorParam::new("initialPtr", KtType::long()))
199 .extends(KtType::cls("NativeHandle"), Some("initialPtr"))
200 .implements(KtType::cls("io.example.api.Describable"))
201 .member(
202 KtFun::new("freePtr")
203 .vis(KtVis::Public)
204 .modifier("override")
205 .param(KtParam::new("ptr", KtType::long()))
206 .body(KtCode::new().line("JNINative.sessionFree(ptr)")),
207 )
208 .member(
209 KtFun::new("describe")
210 .vis(KtVis::Public)
211 .modifier("override")
212 .returns(KtType::string())
213 .expr_body(KtCode::new().line("\"Session(0x${ptr.toString(16)})\"")),
214 )
215 // A generic method whose body uses every `KtCode` block form.
216 .member(
217 KtFun::new("get")
218 .vis(KtVis::Public)
219 .generic("R")
220 .kdoc("Run a query, folding each reply into an accumulator.")
221 .param(KtParam::new("selector", KtType::string()))
222 .param(KtParam::new(
223 "onReply",
224 KtType::lambda(
225 [("reply".to_string(), KtType::cls("io.example.api.Reply"))],
226 KtType::var_r(),
227 ),
228 ))
229 .param(KtParam::new("timeoutMs", KtType::long()).default("10_000L"))
230 .returns(KtType::generic("List", [KtType::var_r()]))
231 .body(
232 KtCode::new()
233 .line("val acc = ArrayList<R>()")
234 .line("val guard = Guard.acquire(this)")
235 .import("io.example.internal.Guard")
236 .try_finally(
237 "",
238 KtCode::new().blk("JNINative.sessionGet(ptr, selector, timeoutMs) { raw ->", |c| {
239 c.line("acc.add(onReply(raw))")
240 }),
241 KtCode::new().line("guard.release()"),
242 )
243 .line("")
244 // A long call that the renderer breaks by width at its
245 // real nesting level.
246 .wline("reportQueryOutcome(selector, timeoutMs, acc.size, acc.isNotEmpty(), \"query finished\", System.nanoTime())")
247 .line("return acc"),
248 ),
249 )
250 // The interface's member extension, implemented.
251 .member(
252 KtFun::new("label")
253 .vis(KtVis::Public)
254 .modifier("override")
255 .receiver(KtType::cls("Sample"))
256 .returns(KtType::string())
257 .expr_body(KtCode::new().line("\"${keyExpr}@${describe()}\"")),
258 )
259 // A member extension of the class itself.
260 .member(
261 KtFun::new("toSample")
262 .vis(KtVis::Public)
263 .receiver(KtType::byte_array())
264 .returns(KtType::cls("Sample"))
265 .expr_body(KtCode::new().line("Sample(describe(), this)")),
266 )
267 // A nested class — its own scope, so its members may reuse names.
268 .member(
269 KtClass::class_("Config")
270 .vis(KtVis::Public)
271 .member(KtProperty::val("describe").initializer("\"config\"")),
272 )
273 .companion(
274 KtCompanion::new()
275 .vis(KtVis::Public)
276 .member(
277 KtFun::new("open")
278 .vis(KtVis::Public)
279 .annotation("JvmStatic")
280 .param(KtParam::new("config", KtType::string()).default("\"{}\""))
281 .returns(KtType::cls("Session"))
282 .expr_body(KtCode::new().line("Session(JNINative.sessionOpen(config))")),
283 ),
284 );
285
286 // A plain `interface`: bodiless members are abstract by position, and a
287 // `KtFunSig` is exactly that.
288 let describable = KtClass::interface_("Describable")
289 .vis(KtVis::Public)
290 .member(KtFunSig::new("describe").returns(KtType::string()))
291 // A member extension: abstract here, supplied by the implementor.
292 // `KtFunSig` carries a receiver too, so a signature does not quietly
293 // become a plain member.
294 .member(
295 KtFunSig::new("label")
296 .receiver(KtType::cls("Sample"))
297 .returns(KtType::string()),
298 );
299
300 // A `fun interface` (SAM) — its single method cannot carry a body.
301 let handler = KtFunInterface::new(
302 "ReplyHandler",
303 KtFunSig::new("onReply")
304 .param(KtParam::new("reply", KtType::cls("Reply")))
305 .returns(KtType::var_r()),
306 )
307 .vis(KtVis::Public)
308 .type_param("out R")
309 .kdoc("Invoked from the native thread for each reply.");
310
311 // Top-level extension functions. The receiver is a type, not part of the
312 // name, so it resolves through the import set and the name stays a plain
313 // identifier the validator can check as one.
314 let summary = KtFun::new("summary")
315 .vis(KtVis::Public)
316 .receiver(KtType::cls("Sample"))
317 .returns(KtType::string())
318 .expr_body(KtCode::new().line("\"$keyExpr (${payload.size} bytes)\""));
319
320 // Generics render before the receiver, which renders before the name.
321 let map_replies = KtFun::new("mapValues")
322 .vis(KtVis::Public)
323 .generic("R")
324 .receiver(KtType::generic("List", [KtType::cls("Reply")]))
325 .param(KtParam::new(
326 "transform",
327 KtType::lambda(
328 [("sample".to_string(), KtType::cls("Sample"))],
329 KtType::var_r(),
330 ),
331 ))
332 .returns(KtType::generic("List", [KtType::var_r()]))
333 .expr_body(
334 KtCode::new().line("filterIsInstance<Reply.Value>().map { transform(it.sample) }"),
335 );
336
337 // An extension on a *function type*. The receiver needs parentheses here
338 // or the `.` would bind to the return type instead.
339 let as_raw = KtFun::new("asRaw")
340 .vis(KtVis::Internal)
341 .receiver(KtType::lambda(
342 [("sample".to_string(), KtType::cls("Sample"))],
343 KtType::unit(),
344 ))
345 .returns(KtType::cls("io.example.api.internal.RawSink"))
346 // The proxy adapts a typed callback to the raw one the natives call,
347 // so it has to narrow `Reply` to the `Sample` the receiver takes.
348 .expr_body(
349 KtCode::new().line("RawSink { raw -> if (raw is Reply.Value) this(raw.sample) }"),
350 );
351
352 KtFile::new("io.example.api")
353 // FQNs named only from raw body text, which the model cannot see.
354 .imports(["io.example.api.internal.JNINative".to_string()])
355 .decl(base)
356 .decl(describable)
357 .decl(handler)
358 .decl(session)
359 .decl(summary)
360 .decl(map_replies)
361 .decl(as_raw)
362 .decl(KtDecl::TypeAlias {
363 vis: KtVis::Public,
364 name: "SampleList".to_string(),
365 target: KtType::generic("List", [KtType::cls("Sample")]),
366 })
367}
368
369/// The `external` surface — an object of natives, in its own subpackage.
370fn natives_fragment() -> KtFile {
371 let natives = KtClass::object_("JNINative")
372 .vis(KtVis::Internal)
373 .kdoc("One-to-one with the exported Rust symbols.")
374 .member(
375 KtFun::new("sessionOpen")
376 .vis(KtVis::Internal)
377 .param(KtParam::new("config", KtType::string()))
378 .returns(KtType::long())
379 .external(),
380 )
381 .member(
382 KtFun::new("sessionFree")
383 .vis(KtVis::Internal)
384 .param(KtParam::new("ptr", KtType::long()))
385 .external(),
386 )
387 .member(
388 KtFun::new("sessionGet")
389 .vis(KtVis::Internal)
390 .param(KtParam::new("ptr", KtType::long()))
391 .param(KtParam::new("selector", KtType::string()))
392 .param(KtParam::new("timeoutMs", KtType::long()))
393 .param(KtParam::new(
394 "sink",
395 KtType::lambda(
396 [("reply".to_string(), KtType::cls("io.example.api.Reply"))],
397 KtType::unit(),
398 ),
399 ))
400 .external(),
401 );
402
403 // A pre-rendered block, for text the model does not describe. Its name is
404 // a merge identity, never emitted.
405 let loader = KtDecl::Raw {
406 name: "__loadNative".to_string(),
407 code: KtCode::raw_reindent(
408 "internal val __loaded: Boolean = run {\n\
409 System.loadLibrary(\"example_jni\")\n\
410 true\n\
411 }",
412 ),
413 };
414
415 let raw_sink = KtFunInterface::new(
416 "RawSink",
417 KtFunSig::new("accept").param(KtParam::new("reply", KtType::cls("io.example.api.Reply"))),
418 )
419 .vis(KtVis::Internal);
420
421 KtFile::new("io.example.api.internal")
422 .decl(raw_sink)
423 .decl(natives)
424 .decl(loader)
425 // An FQN referenced only from raw text the model cannot see.
426 .import("io.example.api.Reply")
427}Sourcepub fn vis(self, v: KtVis) -> Self
pub fn vis(self, v: KtVis) -> Self
Examples found in repository?
examples/showcase.rs (line 307)
164fn session_fragment() -> KtFile {
165 // `abstract class` with an `abstract` member (bodiless, and it says so),
166 // a `@Volatile` property, and an interface it implements.
167 let base = KtClass::class_with(KtClassModifier::Abstract, "NativeHandle")
168 .vis(KtVis::Public)
169 .kdoc("Owns a raw pointer into Rust and frees it exactly once.")
170 .ctor_param(KtCtorParam::new("initialPtr", KtType::long()))
171 .implements(KtType::cls("AutoCloseable"))
172 .member(
173 KtProperty::var("ptr")
174 .ty(KtType::long())
175 .vis(KtVis::Internal)
176 .annotation("Volatile")
177 .kdoc("Zero once closed.")
178 .initializer("initialPtr"),
179 )
180 .member(
181 KtProperty::val("isClosed")
182 .ty(KtType::boolean())
183 .vis(KtVis::Public)
184 .accessors(KtCode::new().line("get() = ptr == 0L")),
185 )
186 .member(
187 KtFun::new("freePtr")
188 .vis(KtVis::Public)
189 .modifier("abstract")
190 .kdoc("Release the native allocation. Called once, under the lock.")
191 .param(KtParam::new("ptr", KtType::long())),
192 );
193
194 // `open class` extending the abstract base and constructing it.
195 let session = KtClass::class_with(KtClassModifier::Open, "Session")
196 .vis(KtVis::Public)
197 .annotation("Suppress(\"unused\")")
198 .ctor_param(KtCtorParam::new("initialPtr", KtType::long()))
199 .extends(KtType::cls("NativeHandle"), Some("initialPtr"))
200 .implements(KtType::cls("io.example.api.Describable"))
201 .member(
202 KtFun::new("freePtr")
203 .vis(KtVis::Public)
204 .modifier("override")
205 .param(KtParam::new("ptr", KtType::long()))
206 .body(KtCode::new().line("JNINative.sessionFree(ptr)")),
207 )
208 .member(
209 KtFun::new("describe")
210 .vis(KtVis::Public)
211 .modifier("override")
212 .returns(KtType::string())
213 .expr_body(KtCode::new().line("\"Session(0x${ptr.toString(16)})\"")),
214 )
215 // A generic method whose body uses every `KtCode` block form.
216 .member(
217 KtFun::new("get")
218 .vis(KtVis::Public)
219 .generic("R")
220 .kdoc("Run a query, folding each reply into an accumulator.")
221 .param(KtParam::new("selector", KtType::string()))
222 .param(KtParam::new(
223 "onReply",
224 KtType::lambda(
225 [("reply".to_string(), KtType::cls("io.example.api.Reply"))],
226 KtType::var_r(),
227 ),
228 ))
229 .param(KtParam::new("timeoutMs", KtType::long()).default("10_000L"))
230 .returns(KtType::generic("List", [KtType::var_r()]))
231 .body(
232 KtCode::new()
233 .line("val acc = ArrayList<R>()")
234 .line("val guard = Guard.acquire(this)")
235 .import("io.example.internal.Guard")
236 .try_finally(
237 "",
238 KtCode::new().blk("JNINative.sessionGet(ptr, selector, timeoutMs) { raw ->", |c| {
239 c.line("acc.add(onReply(raw))")
240 }),
241 KtCode::new().line("guard.release()"),
242 )
243 .line("")
244 // A long call that the renderer breaks by width at its
245 // real nesting level.
246 .wline("reportQueryOutcome(selector, timeoutMs, acc.size, acc.isNotEmpty(), \"query finished\", System.nanoTime())")
247 .line("return acc"),
248 ),
249 )
250 // The interface's member extension, implemented.
251 .member(
252 KtFun::new("label")
253 .vis(KtVis::Public)
254 .modifier("override")
255 .receiver(KtType::cls("Sample"))
256 .returns(KtType::string())
257 .expr_body(KtCode::new().line("\"${keyExpr}@${describe()}\"")),
258 )
259 // A member extension of the class itself.
260 .member(
261 KtFun::new("toSample")
262 .vis(KtVis::Public)
263 .receiver(KtType::byte_array())
264 .returns(KtType::cls("Sample"))
265 .expr_body(KtCode::new().line("Sample(describe(), this)")),
266 )
267 // A nested class — its own scope, so its members may reuse names.
268 .member(
269 KtClass::class_("Config")
270 .vis(KtVis::Public)
271 .member(KtProperty::val("describe").initializer("\"config\"")),
272 )
273 .companion(
274 KtCompanion::new()
275 .vis(KtVis::Public)
276 .member(
277 KtFun::new("open")
278 .vis(KtVis::Public)
279 .annotation("JvmStatic")
280 .param(KtParam::new("config", KtType::string()).default("\"{}\""))
281 .returns(KtType::cls("Session"))
282 .expr_body(KtCode::new().line("Session(JNINative.sessionOpen(config))")),
283 ),
284 );
285
286 // A plain `interface`: bodiless members are abstract by position, and a
287 // `KtFunSig` is exactly that.
288 let describable = KtClass::interface_("Describable")
289 .vis(KtVis::Public)
290 .member(KtFunSig::new("describe").returns(KtType::string()))
291 // A member extension: abstract here, supplied by the implementor.
292 // `KtFunSig` carries a receiver too, so a signature does not quietly
293 // become a plain member.
294 .member(
295 KtFunSig::new("label")
296 .receiver(KtType::cls("Sample"))
297 .returns(KtType::string()),
298 );
299
300 // A `fun interface` (SAM) — its single method cannot carry a body.
301 let handler = KtFunInterface::new(
302 "ReplyHandler",
303 KtFunSig::new("onReply")
304 .param(KtParam::new("reply", KtType::cls("Reply")))
305 .returns(KtType::var_r()),
306 )
307 .vis(KtVis::Public)
308 .type_param("out R")
309 .kdoc("Invoked from the native thread for each reply.");
310
311 // Top-level extension functions. The receiver is a type, not part of the
312 // name, so it resolves through the import set and the name stays a plain
313 // identifier the validator can check as one.
314 let summary = KtFun::new("summary")
315 .vis(KtVis::Public)
316 .receiver(KtType::cls("Sample"))
317 .returns(KtType::string())
318 .expr_body(KtCode::new().line("\"$keyExpr (${payload.size} bytes)\""));
319
320 // Generics render before the receiver, which renders before the name.
321 let map_replies = KtFun::new("mapValues")
322 .vis(KtVis::Public)
323 .generic("R")
324 .receiver(KtType::generic("List", [KtType::cls("Reply")]))
325 .param(KtParam::new(
326 "transform",
327 KtType::lambda(
328 [("sample".to_string(), KtType::cls("Sample"))],
329 KtType::var_r(),
330 ),
331 ))
332 .returns(KtType::generic("List", [KtType::var_r()]))
333 .expr_body(
334 KtCode::new().line("filterIsInstance<Reply.Value>().map { transform(it.sample) }"),
335 );
336
337 // An extension on a *function type*. The receiver needs parentheses here
338 // or the `.` would bind to the return type instead.
339 let as_raw = KtFun::new("asRaw")
340 .vis(KtVis::Internal)
341 .receiver(KtType::lambda(
342 [("sample".to_string(), KtType::cls("Sample"))],
343 KtType::unit(),
344 ))
345 .returns(KtType::cls("io.example.api.internal.RawSink"))
346 // The proxy adapts a typed callback to the raw one the natives call,
347 // so it has to narrow `Reply` to the `Sample` the receiver takes.
348 .expr_body(
349 KtCode::new().line("RawSink { raw -> if (raw is Reply.Value) this(raw.sample) }"),
350 );
351
352 KtFile::new("io.example.api")
353 // FQNs named only from raw body text, which the model cannot see.
354 .imports(["io.example.api.internal.JNINative".to_string()])
355 .decl(base)
356 .decl(describable)
357 .decl(handler)
358 .decl(session)
359 .decl(summary)
360 .decl(map_replies)
361 .decl(as_raw)
362 .decl(KtDecl::TypeAlias {
363 vis: KtVis::Public,
364 name: "SampleList".to_string(),
365 target: KtType::generic("List", [KtType::cls("Sample")]),
366 })
367}
368
369/// The `external` surface — an object of natives, in its own subpackage.
370fn natives_fragment() -> KtFile {
371 let natives = KtClass::object_("JNINative")
372 .vis(KtVis::Internal)
373 .kdoc("One-to-one with the exported Rust symbols.")
374 .member(
375 KtFun::new("sessionOpen")
376 .vis(KtVis::Internal)
377 .param(KtParam::new("config", KtType::string()))
378 .returns(KtType::long())
379 .external(),
380 )
381 .member(
382 KtFun::new("sessionFree")
383 .vis(KtVis::Internal)
384 .param(KtParam::new("ptr", KtType::long()))
385 .external(),
386 )
387 .member(
388 KtFun::new("sessionGet")
389 .vis(KtVis::Internal)
390 .param(KtParam::new("ptr", KtType::long()))
391 .param(KtParam::new("selector", KtType::string()))
392 .param(KtParam::new("timeoutMs", KtType::long()))
393 .param(KtParam::new(
394 "sink",
395 KtType::lambda(
396 [("reply".to_string(), KtType::cls("io.example.api.Reply"))],
397 KtType::unit(),
398 ),
399 ))
400 .external(),
401 );
402
403 // A pre-rendered block, for text the model does not describe. Its name is
404 // a merge identity, never emitted.
405 let loader = KtDecl::Raw {
406 name: "__loadNative".to_string(),
407 code: KtCode::raw_reindent(
408 "internal val __loaded: Boolean = run {\n\
409 System.loadLibrary(\"example_jni\")\n\
410 true\n\
411 }",
412 ),
413 };
414
415 let raw_sink = KtFunInterface::new(
416 "RawSink",
417 KtFunSig::new("accept").param(KtParam::new("reply", KtType::cls("io.example.api.Reply"))),
418 )
419 .vis(KtVis::Internal);
420
421 KtFile::new("io.example.api.internal")
422 .decl(raw_sink)
423 .decl(natives)
424 .decl(loader)
425 // An FQN referenced only from raw text the model cannot see.
426 .import("io.example.api.Reply")
427}Sourcepub fn type_param(self, p: impl Into<String>) -> Self
pub fn type_param(self, p: impl Into<String>) -> Self
Examples found in repository?
examples/showcase.rs (line 308)
164fn session_fragment() -> KtFile {
165 // `abstract class` with an `abstract` member (bodiless, and it says so),
166 // a `@Volatile` property, and an interface it implements.
167 let base = KtClass::class_with(KtClassModifier::Abstract, "NativeHandle")
168 .vis(KtVis::Public)
169 .kdoc("Owns a raw pointer into Rust and frees it exactly once.")
170 .ctor_param(KtCtorParam::new("initialPtr", KtType::long()))
171 .implements(KtType::cls("AutoCloseable"))
172 .member(
173 KtProperty::var("ptr")
174 .ty(KtType::long())
175 .vis(KtVis::Internal)
176 .annotation("Volatile")
177 .kdoc("Zero once closed.")
178 .initializer("initialPtr"),
179 )
180 .member(
181 KtProperty::val("isClosed")
182 .ty(KtType::boolean())
183 .vis(KtVis::Public)
184 .accessors(KtCode::new().line("get() = ptr == 0L")),
185 )
186 .member(
187 KtFun::new("freePtr")
188 .vis(KtVis::Public)
189 .modifier("abstract")
190 .kdoc("Release the native allocation. Called once, under the lock.")
191 .param(KtParam::new("ptr", KtType::long())),
192 );
193
194 // `open class` extending the abstract base and constructing it.
195 let session = KtClass::class_with(KtClassModifier::Open, "Session")
196 .vis(KtVis::Public)
197 .annotation("Suppress(\"unused\")")
198 .ctor_param(KtCtorParam::new("initialPtr", KtType::long()))
199 .extends(KtType::cls("NativeHandle"), Some("initialPtr"))
200 .implements(KtType::cls("io.example.api.Describable"))
201 .member(
202 KtFun::new("freePtr")
203 .vis(KtVis::Public)
204 .modifier("override")
205 .param(KtParam::new("ptr", KtType::long()))
206 .body(KtCode::new().line("JNINative.sessionFree(ptr)")),
207 )
208 .member(
209 KtFun::new("describe")
210 .vis(KtVis::Public)
211 .modifier("override")
212 .returns(KtType::string())
213 .expr_body(KtCode::new().line("\"Session(0x${ptr.toString(16)})\"")),
214 )
215 // A generic method whose body uses every `KtCode` block form.
216 .member(
217 KtFun::new("get")
218 .vis(KtVis::Public)
219 .generic("R")
220 .kdoc("Run a query, folding each reply into an accumulator.")
221 .param(KtParam::new("selector", KtType::string()))
222 .param(KtParam::new(
223 "onReply",
224 KtType::lambda(
225 [("reply".to_string(), KtType::cls("io.example.api.Reply"))],
226 KtType::var_r(),
227 ),
228 ))
229 .param(KtParam::new("timeoutMs", KtType::long()).default("10_000L"))
230 .returns(KtType::generic("List", [KtType::var_r()]))
231 .body(
232 KtCode::new()
233 .line("val acc = ArrayList<R>()")
234 .line("val guard = Guard.acquire(this)")
235 .import("io.example.internal.Guard")
236 .try_finally(
237 "",
238 KtCode::new().blk("JNINative.sessionGet(ptr, selector, timeoutMs) { raw ->", |c| {
239 c.line("acc.add(onReply(raw))")
240 }),
241 KtCode::new().line("guard.release()"),
242 )
243 .line("")
244 // A long call that the renderer breaks by width at its
245 // real nesting level.
246 .wline("reportQueryOutcome(selector, timeoutMs, acc.size, acc.isNotEmpty(), \"query finished\", System.nanoTime())")
247 .line("return acc"),
248 ),
249 )
250 // The interface's member extension, implemented.
251 .member(
252 KtFun::new("label")
253 .vis(KtVis::Public)
254 .modifier("override")
255 .receiver(KtType::cls("Sample"))
256 .returns(KtType::string())
257 .expr_body(KtCode::new().line("\"${keyExpr}@${describe()}\"")),
258 )
259 // A member extension of the class itself.
260 .member(
261 KtFun::new("toSample")
262 .vis(KtVis::Public)
263 .receiver(KtType::byte_array())
264 .returns(KtType::cls("Sample"))
265 .expr_body(KtCode::new().line("Sample(describe(), this)")),
266 )
267 // A nested class — its own scope, so its members may reuse names.
268 .member(
269 KtClass::class_("Config")
270 .vis(KtVis::Public)
271 .member(KtProperty::val("describe").initializer("\"config\"")),
272 )
273 .companion(
274 KtCompanion::new()
275 .vis(KtVis::Public)
276 .member(
277 KtFun::new("open")
278 .vis(KtVis::Public)
279 .annotation("JvmStatic")
280 .param(KtParam::new("config", KtType::string()).default("\"{}\""))
281 .returns(KtType::cls("Session"))
282 .expr_body(KtCode::new().line("Session(JNINative.sessionOpen(config))")),
283 ),
284 );
285
286 // A plain `interface`: bodiless members are abstract by position, and a
287 // `KtFunSig` is exactly that.
288 let describable = KtClass::interface_("Describable")
289 .vis(KtVis::Public)
290 .member(KtFunSig::new("describe").returns(KtType::string()))
291 // A member extension: abstract here, supplied by the implementor.
292 // `KtFunSig` carries a receiver too, so a signature does not quietly
293 // become a plain member.
294 .member(
295 KtFunSig::new("label")
296 .receiver(KtType::cls("Sample"))
297 .returns(KtType::string()),
298 );
299
300 // A `fun interface` (SAM) — its single method cannot carry a body.
301 let handler = KtFunInterface::new(
302 "ReplyHandler",
303 KtFunSig::new("onReply")
304 .param(KtParam::new("reply", KtType::cls("Reply")))
305 .returns(KtType::var_r()),
306 )
307 .vis(KtVis::Public)
308 .type_param("out R")
309 .kdoc("Invoked from the native thread for each reply.");
310
311 // Top-level extension functions. The receiver is a type, not part of the
312 // name, so it resolves through the import set and the name stays a plain
313 // identifier the validator can check as one.
314 let summary = KtFun::new("summary")
315 .vis(KtVis::Public)
316 .receiver(KtType::cls("Sample"))
317 .returns(KtType::string())
318 .expr_body(KtCode::new().line("\"$keyExpr (${payload.size} bytes)\""));
319
320 // Generics render before the receiver, which renders before the name.
321 let map_replies = KtFun::new("mapValues")
322 .vis(KtVis::Public)
323 .generic("R")
324 .receiver(KtType::generic("List", [KtType::cls("Reply")]))
325 .param(KtParam::new(
326 "transform",
327 KtType::lambda(
328 [("sample".to_string(), KtType::cls("Sample"))],
329 KtType::var_r(),
330 ),
331 ))
332 .returns(KtType::generic("List", [KtType::var_r()]))
333 .expr_body(
334 KtCode::new().line("filterIsInstance<Reply.Value>().map { transform(it.sample) }"),
335 );
336
337 // An extension on a *function type*. The receiver needs parentheses here
338 // or the `.` would bind to the return type instead.
339 let as_raw = KtFun::new("asRaw")
340 .vis(KtVis::Internal)
341 .receiver(KtType::lambda(
342 [("sample".to_string(), KtType::cls("Sample"))],
343 KtType::unit(),
344 ))
345 .returns(KtType::cls("io.example.api.internal.RawSink"))
346 // The proxy adapts a typed callback to the raw one the natives call,
347 // so it has to narrow `Reply` to the `Sample` the receiver takes.
348 .expr_body(
349 KtCode::new().line("RawSink { raw -> if (raw is Reply.Value) this(raw.sample) }"),
350 );
351
352 KtFile::new("io.example.api")
353 // FQNs named only from raw body text, which the model cannot see.
354 .imports(["io.example.api.internal.JNINative".to_string()])
355 .decl(base)
356 .decl(describable)
357 .decl(handler)
358 .decl(session)
359 .decl(summary)
360 .decl(map_replies)
361 .decl(as_raw)
362 .decl(KtDecl::TypeAlias {
363 vis: KtVis::Public,
364 name: "SampleList".to_string(),
365 target: KtType::generic("List", [KtType::cls("Sample")]),
366 })
367}Sourcepub fn kdoc(self, d: impl Into<String>) -> Self
pub fn kdoc(self, d: impl Into<String>) -> Self
Examples found in repository?
examples/showcase.rs (line 309)
164fn session_fragment() -> KtFile {
165 // `abstract class` with an `abstract` member (bodiless, and it says so),
166 // a `@Volatile` property, and an interface it implements.
167 let base = KtClass::class_with(KtClassModifier::Abstract, "NativeHandle")
168 .vis(KtVis::Public)
169 .kdoc("Owns a raw pointer into Rust and frees it exactly once.")
170 .ctor_param(KtCtorParam::new("initialPtr", KtType::long()))
171 .implements(KtType::cls("AutoCloseable"))
172 .member(
173 KtProperty::var("ptr")
174 .ty(KtType::long())
175 .vis(KtVis::Internal)
176 .annotation("Volatile")
177 .kdoc("Zero once closed.")
178 .initializer("initialPtr"),
179 )
180 .member(
181 KtProperty::val("isClosed")
182 .ty(KtType::boolean())
183 .vis(KtVis::Public)
184 .accessors(KtCode::new().line("get() = ptr == 0L")),
185 )
186 .member(
187 KtFun::new("freePtr")
188 .vis(KtVis::Public)
189 .modifier("abstract")
190 .kdoc("Release the native allocation. Called once, under the lock.")
191 .param(KtParam::new("ptr", KtType::long())),
192 );
193
194 // `open class` extending the abstract base and constructing it.
195 let session = KtClass::class_with(KtClassModifier::Open, "Session")
196 .vis(KtVis::Public)
197 .annotation("Suppress(\"unused\")")
198 .ctor_param(KtCtorParam::new("initialPtr", KtType::long()))
199 .extends(KtType::cls("NativeHandle"), Some("initialPtr"))
200 .implements(KtType::cls("io.example.api.Describable"))
201 .member(
202 KtFun::new("freePtr")
203 .vis(KtVis::Public)
204 .modifier("override")
205 .param(KtParam::new("ptr", KtType::long()))
206 .body(KtCode::new().line("JNINative.sessionFree(ptr)")),
207 )
208 .member(
209 KtFun::new("describe")
210 .vis(KtVis::Public)
211 .modifier("override")
212 .returns(KtType::string())
213 .expr_body(KtCode::new().line("\"Session(0x${ptr.toString(16)})\"")),
214 )
215 // A generic method whose body uses every `KtCode` block form.
216 .member(
217 KtFun::new("get")
218 .vis(KtVis::Public)
219 .generic("R")
220 .kdoc("Run a query, folding each reply into an accumulator.")
221 .param(KtParam::new("selector", KtType::string()))
222 .param(KtParam::new(
223 "onReply",
224 KtType::lambda(
225 [("reply".to_string(), KtType::cls("io.example.api.Reply"))],
226 KtType::var_r(),
227 ),
228 ))
229 .param(KtParam::new("timeoutMs", KtType::long()).default("10_000L"))
230 .returns(KtType::generic("List", [KtType::var_r()]))
231 .body(
232 KtCode::new()
233 .line("val acc = ArrayList<R>()")
234 .line("val guard = Guard.acquire(this)")
235 .import("io.example.internal.Guard")
236 .try_finally(
237 "",
238 KtCode::new().blk("JNINative.sessionGet(ptr, selector, timeoutMs) { raw ->", |c| {
239 c.line("acc.add(onReply(raw))")
240 }),
241 KtCode::new().line("guard.release()"),
242 )
243 .line("")
244 // A long call that the renderer breaks by width at its
245 // real nesting level.
246 .wline("reportQueryOutcome(selector, timeoutMs, acc.size, acc.isNotEmpty(), \"query finished\", System.nanoTime())")
247 .line("return acc"),
248 ),
249 )
250 // The interface's member extension, implemented.
251 .member(
252 KtFun::new("label")
253 .vis(KtVis::Public)
254 .modifier("override")
255 .receiver(KtType::cls("Sample"))
256 .returns(KtType::string())
257 .expr_body(KtCode::new().line("\"${keyExpr}@${describe()}\"")),
258 )
259 // A member extension of the class itself.
260 .member(
261 KtFun::new("toSample")
262 .vis(KtVis::Public)
263 .receiver(KtType::byte_array())
264 .returns(KtType::cls("Sample"))
265 .expr_body(KtCode::new().line("Sample(describe(), this)")),
266 )
267 // A nested class — its own scope, so its members may reuse names.
268 .member(
269 KtClass::class_("Config")
270 .vis(KtVis::Public)
271 .member(KtProperty::val("describe").initializer("\"config\"")),
272 )
273 .companion(
274 KtCompanion::new()
275 .vis(KtVis::Public)
276 .member(
277 KtFun::new("open")
278 .vis(KtVis::Public)
279 .annotation("JvmStatic")
280 .param(KtParam::new("config", KtType::string()).default("\"{}\""))
281 .returns(KtType::cls("Session"))
282 .expr_body(KtCode::new().line("Session(JNINative.sessionOpen(config))")),
283 ),
284 );
285
286 // A plain `interface`: bodiless members are abstract by position, and a
287 // `KtFunSig` is exactly that.
288 let describable = KtClass::interface_("Describable")
289 .vis(KtVis::Public)
290 .member(KtFunSig::new("describe").returns(KtType::string()))
291 // A member extension: abstract here, supplied by the implementor.
292 // `KtFunSig` carries a receiver too, so a signature does not quietly
293 // become a plain member.
294 .member(
295 KtFunSig::new("label")
296 .receiver(KtType::cls("Sample"))
297 .returns(KtType::string()),
298 );
299
300 // A `fun interface` (SAM) — its single method cannot carry a body.
301 let handler = KtFunInterface::new(
302 "ReplyHandler",
303 KtFunSig::new("onReply")
304 .param(KtParam::new("reply", KtType::cls("Reply")))
305 .returns(KtType::var_r()),
306 )
307 .vis(KtVis::Public)
308 .type_param("out R")
309 .kdoc("Invoked from the native thread for each reply.");
310
311 // Top-level extension functions. The receiver is a type, not part of the
312 // name, so it resolves through the import set and the name stays a plain
313 // identifier the validator can check as one.
314 let summary = KtFun::new("summary")
315 .vis(KtVis::Public)
316 .receiver(KtType::cls("Sample"))
317 .returns(KtType::string())
318 .expr_body(KtCode::new().line("\"$keyExpr (${payload.size} bytes)\""));
319
320 // Generics render before the receiver, which renders before the name.
321 let map_replies = KtFun::new("mapValues")
322 .vis(KtVis::Public)
323 .generic("R")
324 .receiver(KtType::generic("List", [KtType::cls("Reply")]))
325 .param(KtParam::new(
326 "transform",
327 KtType::lambda(
328 [("sample".to_string(), KtType::cls("Sample"))],
329 KtType::var_r(),
330 ),
331 ))
332 .returns(KtType::generic("List", [KtType::var_r()]))
333 .expr_body(
334 KtCode::new().line("filterIsInstance<Reply.Value>().map { transform(it.sample) }"),
335 );
336
337 // An extension on a *function type*. The receiver needs parentheses here
338 // or the `.` would bind to the return type instead.
339 let as_raw = KtFun::new("asRaw")
340 .vis(KtVis::Internal)
341 .receiver(KtType::lambda(
342 [("sample".to_string(), KtType::cls("Sample"))],
343 KtType::unit(),
344 ))
345 .returns(KtType::cls("io.example.api.internal.RawSink"))
346 // The proxy adapts a typed callback to the raw one the natives call,
347 // so it has to narrow `Reply` to the `Sample` the receiver takes.
348 .expr_body(
349 KtCode::new().line("RawSink { raw -> if (raw is Reply.Value) this(raw.sample) }"),
350 );
351
352 KtFile::new("io.example.api")
353 // FQNs named only from raw body text, which the model cannot see.
354 .imports(["io.example.api.internal.JNINative".to_string()])
355 .decl(base)
356 .decl(describable)
357 .decl(handler)
358 .decl(session)
359 .decl(summary)
360 .decl(map_replies)
361 .decl(as_raw)
362 .decl(KtDecl::TypeAlias {
363 vis: KtVis::Public,
364 name: "SampleList".to_string(),
365 target: KtType::generic("List", [KtType::cls("Sample")]),
366 })
367}Trait Implementations§
Source§impl Clone for KtFunInterface
impl Clone for KtFunInterface
Source§fn clone(&self) -> KtFunInterface
fn clone(&self) -> KtFunInterface
Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreSource§impl Debug for KtFunInterface
impl Debug for KtFunInterface
Source§impl From<KtFunInterface> for KtDecl
impl From<KtFunInterface> for KtDecl
Source§fn from(i: KtFunInterface) -> Self
fn from(i: KtFunInterface) -> Self
Converts to this type from the input type.
Auto Trait Implementations§
impl Freeze for KtFunInterface
impl RefUnwindSafe for KtFunInterface
impl Send for KtFunInterface
impl Sync for KtFunInterface
impl Unpin for KtFunInterface
impl UnsafeUnpin for KtFunInterface
impl UnwindSafe for KtFunInterface
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more