pub struct KtProperty {
pub name: String,
pub ty: Option<KtType>,
pub value: KtPropertyValue,
pub mutable: bool,
pub vis: KtVis,
pub annotations: Vec<String>,
pub modifiers: Vec<String>,
pub kdoc: Option<String>,
pub accessors: Option<KtCode>,
}Expand description
A property declaration (top-level or member).
Fields§
§name: String§ty: Option<KtType>§value: KtPropertyValueThe initializer or the delegate — never both. The exclusion used to
be two Option<String> fields plus a doc comment and a debug_assert;
it is now a sum, so the illegal state is unrepresentable.
mutable: bool§vis: KtVis§annotations: Vec<String>Inline annotations rendered before the keyword: @Volatile internal var ….
modifiers: Vec<String>Keyword modifiers rendered between visibility and val/var
(open, final override, …).
kdoc: Option<String>§accessors: Option<KtCode>Accessor code rendered after the property declaration.
Implementations§
Source§impl KtProperty
impl KtProperty
Sourcepub fn val(name: impl Into<String>) -> Self
pub fn val(name: impl Into<String>) -> Self
Examples found in repository?
examples/invalid.rs (line 128)
71fn broken_declarations() -> KtFile {
72 KtFile::new("io.example.broken")
73 // Two classes of the same name: a redeclaration in the type namespace.
74 .decl(KtClass::class_("Session"))
75 .decl(KtClass::class_("Session"))
76 // An interface and a type alias are both classifier declarations, so they collide.
77 .decl(
78 KtClass::interface_("Describable")
79 .member(KtFun::new("describe").returns(KtType::string())),
80 )
81 .decl(KtDecl::TypeAlias {
82 vis: KtVis::Public,
83 name: "Describable".to_string(),
84 target: KtType::string(),
85 })
86 // Same name AND same parameter types: not an overload.
87 .decl(
88 KtFun::new("send")
89 .param(KtParam::new("value", KtType::int()))
90 .returns(KtType::boolean())
91 .body(KtCode::new()),
92 )
93 .decl(
94 KtFun::new("send")
95 .param(KtParam::new("other", KtType::int()))
96 .returns(KtType::long())
97 .body(KtCode::new()),
98 )
99 // Extensions are keyed on their receiver, so these two collide while
100 // the same pair on different receivers would not.
101 .decl(
102 KtFun::new("asRaw")
103 .receiver(KtType::cls("io.example.Codec"))
104 .body(KtCode::new()),
105 )
106 .decl(
107 KtFun::new("asRaw")
108 .receiver(KtType::cls("io.example.Codec"))
109 .body(KtCode::new()),
110 )
111 // ...as here: same name, different receiver, no diagnostic.
112 .decl(
113 KtFun::new("asRaw")
114 .receiver(KtType::cls("io.example.Other"))
115 .body(KtCode::new()),
116 )
117 // Names that are not legal Kotlin identifiers.
118 .decl(
119 KtClass::class_("My-Class")
120 .ctor_param(KtCtorParam::new("2fast", KtType::int()))
121 .member(
122 KtFun::new("object")
123 .param(KtParam::new("in", KtType::int()))
124 .body(KtCode::new()),
125 ),
126 )
127 // `val x` with no type, no value and no accessors.
128 .decl(KtProperty::val("bare"))
129 // A function with no body, at top level, where that cannot mean
130 // "abstract".
131 .decl(KtFun::new("nobody"))
132 // An abstract class member missing the `abstract` keyword.
133 .decl(
134 KtClass::class_with(KtClassModifier::Abstract, "Base")
135 .member(KtFun::new("unimplemented")),
136 )
137 // An enum whose entries do not call the constructor it declares.
138 .decl(
139 KtClass::enum_("Priority")
140 .ctor_param(KtCtorParam::new("code", KtType::int()).val())
141 .entry(KtEnumEntry::with_args("HIGH", "1"))
142 .entry(KtEnumEntry::new("LOW")),
143 )
144 // A constructor property and a member property of one name: both live
145 // in the value namespace.
146 .decl(
147 KtClass::class_("Holder")
148 .ctor_param(KtCtorParam::new("id", KtType::long()).val())
149 .member(KtProperty::val("id").initializer("0")),
150 )
151 // A named companion object colliding with a nested class.
152 .decl(
153 KtClass::class_("Outer")
154 .member(KtClass::class_("Factory"))
155 .companion(KtCompanion::named("Factory")),
156 )
157 // Two raw blocks claiming one identity with different bodies.
158 .decl(KtDecl::Raw {
159 name: "__loader".to_string(),
160 code: KtCode::new().line("internal val __loader = 1"),
161 })
162 .decl(KtDecl::Raw {
163 name: "__loader".to_string(),
164 code: KtCode::new().line("internal val __loader = 2"),
165 })
166 // Two different classes referenced from raw text under one short name:
167 // the text already says `Codec`, so it cannot mean both.
168 .import("io.example.a.Codec")
169 .import("io.example.b.Codec")
170}More examples
examples/showcase.rs (line 181)
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}
428
429/// A file in the default (root) package, exercising a banner override and
430/// top-level declarations of every value kind.
431fn root_fragment() -> KtFile {
432 KtFile::new("")
433 .banner("// Hand-tuned banner for the root package.")
434 .decl(
435 KtProperty::val("LIBRARY_VERSION")
436 .ty(KtType::string())
437 .vis(KtVis::Public)
438 .kdoc("Version this binding was generated against.")
439 .initializer("\"1.9.0\""),
440 )
441 // A keyword modifier rendered between visibility and `val`.
442 .decl(
443 KtProperty::val("PROTOCOL")
444 .ty(KtType::string())
445 .vis(KtVis::Public)
446 .modifier("const")
447 .initializer("\"tcp\""),
448 )
449 // A delegated property: `by <expr>` rather than `= <expr>`.
450 .decl(
451 KtProperty::val("defaultTimeout")
452 .vis(KtVis::Internal)
453 .ty(KtType::cls("java.time.Duration"))
454 .delegate("lazy { Duration.ofSeconds(10) }"),
455 )
456 .decl(
457 KtFun::new("describeAll")
458 .vis(KtVis::Public)
459 // Generic parameter lists are free-form text, so a bound is
460 // written as given — it is not shortened against the imports.
461 .generic("T : io.example.api.Describable")
462 .param(KtParam::new(
463 "items",
464 KtType::generic("List", [KtType::var_("T")]),
465 ))
466 .returns(KtType::string())
467 .expr_body(KtCode::new().line("items.joinToString { it.describe() }")),
468 )
469}Sourcepub fn var(name: impl Into<String>) -> Self
pub fn var(name: impl Into<String>) -> Self
Examples found in repository?
examples/showcase.rs (line 173)
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 ty(self, t: KtType) -> Self
pub fn ty(self, t: KtType) -> Self
Examples found in repository?
examples/showcase.rs (line 174)
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}
428
429/// A file in the default (root) package, exercising a banner override and
430/// top-level declarations of every value kind.
431fn root_fragment() -> KtFile {
432 KtFile::new("")
433 .banner("// Hand-tuned banner for the root package.")
434 .decl(
435 KtProperty::val("LIBRARY_VERSION")
436 .ty(KtType::string())
437 .vis(KtVis::Public)
438 .kdoc("Version this binding was generated against.")
439 .initializer("\"1.9.0\""),
440 )
441 // A keyword modifier rendered between visibility and `val`.
442 .decl(
443 KtProperty::val("PROTOCOL")
444 .ty(KtType::string())
445 .vis(KtVis::Public)
446 .modifier("const")
447 .initializer("\"tcp\""),
448 )
449 // A delegated property: `by <expr>` rather than `= <expr>`.
450 .decl(
451 KtProperty::val("defaultTimeout")
452 .vis(KtVis::Internal)
453 .ty(KtType::cls("java.time.Duration"))
454 .delegate("lazy { Duration.ofSeconds(10) }"),
455 )
456 .decl(
457 KtFun::new("describeAll")
458 .vis(KtVis::Public)
459 // Generic parameter lists are free-form text, so a bound is
460 // written as given — it is not shortened against the imports.
461 .generic("T : io.example.api.Describable")
462 .param(KtParam::new(
463 "items",
464 KtType::generic("List", [KtType::var_("T")]),
465 ))
466 .returns(KtType::string())
467 .expr_body(KtCode::new().line("items.joinToString { it.describe() }")),
468 )
469}Sourcepub fn initializer(self, i: impl Into<String>) -> Self
pub fn initializer(self, i: impl Into<String>) -> Self
Examples found in repository?
examples/invalid.rs (line 149)
71fn broken_declarations() -> KtFile {
72 KtFile::new("io.example.broken")
73 // Two classes of the same name: a redeclaration in the type namespace.
74 .decl(KtClass::class_("Session"))
75 .decl(KtClass::class_("Session"))
76 // An interface and a type alias are both classifier declarations, so they collide.
77 .decl(
78 KtClass::interface_("Describable")
79 .member(KtFun::new("describe").returns(KtType::string())),
80 )
81 .decl(KtDecl::TypeAlias {
82 vis: KtVis::Public,
83 name: "Describable".to_string(),
84 target: KtType::string(),
85 })
86 // Same name AND same parameter types: not an overload.
87 .decl(
88 KtFun::new("send")
89 .param(KtParam::new("value", KtType::int()))
90 .returns(KtType::boolean())
91 .body(KtCode::new()),
92 )
93 .decl(
94 KtFun::new("send")
95 .param(KtParam::new("other", KtType::int()))
96 .returns(KtType::long())
97 .body(KtCode::new()),
98 )
99 // Extensions are keyed on their receiver, so these two collide while
100 // the same pair on different receivers would not.
101 .decl(
102 KtFun::new("asRaw")
103 .receiver(KtType::cls("io.example.Codec"))
104 .body(KtCode::new()),
105 )
106 .decl(
107 KtFun::new("asRaw")
108 .receiver(KtType::cls("io.example.Codec"))
109 .body(KtCode::new()),
110 )
111 // ...as here: same name, different receiver, no diagnostic.
112 .decl(
113 KtFun::new("asRaw")
114 .receiver(KtType::cls("io.example.Other"))
115 .body(KtCode::new()),
116 )
117 // Names that are not legal Kotlin identifiers.
118 .decl(
119 KtClass::class_("My-Class")
120 .ctor_param(KtCtorParam::new("2fast", KtType::int()))
121 .member(
122 KtFun::new("object")
123 .param(KtParam::new("in", KtType::int()))
124 .body(KtCode::new()),
125 ),
126 )
127 // `val x` with no type, no value and no accessors.
128 .decl(KtProperty::val("bare"))
129 // A function with no body, at top level, where that cannot mean
130 // "abstract".
131 .decl(KtFun::new("nobody"))
132 // An abstract class member missing the `abstract` keyword.
133 .decl(
134 KtClass::class_with(KtClassModifier::Abstract, "Base")
135 .member(KtFun::new("unimplemented")),
136 )
137 // An enum whose entries do not call the constructor it declares.
138 .decl(
139 KtClass::enum_("Priority")
140 .ctor_param(KtCtorParam::new("code", KtType::int()).val())
141 .entry(KtEnumEntry::with_args("HIGH", "1"))
142 .entry(KtEnumEntry::new("LOW")),
143 )
144 // A constructor property and a member property of one name: both live
145 // in the value namespace.
146 .decl(
147 KtClass::class_("Holder")
148 .ctor_param(KtCtorParam::new("id", KtType::long()).val())
149 .member(KtProperty::val("id").initializer("0")),
150 )
151 // A named companion object colliding with a nested class.
152 .decl(
153 KtClass::class_("Outer")
154 .member(KtClass::class_("Factory"))
155 .companion(KtCompanion::named("Factory")),
156 )
157 // Two raw blocks claiming one identity with different bodies.
158 .decl(KtDecl::Raw {
159 name: "__loader".to_string(),
160 code: KtCode::new().line("internal val __loader = 1"),
161 })
162 .decl(KtDecl::Raw {
163 name: "__loader".to_string(),
164 code: KtCode::new().line("internal val __loader = 2"),
165 })
166 // Two different classes referenced from raw text under one short name:
167 // the text already says `Codec`, so it cannot mean both.
168 .import("io.example.a.Codec")
169 .import("io.example.b.Codec")
170}More examples
examples/showcase.rs (line 178)
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}
428
429/// A file in the default (root) package, exercising a banner override and
430/// top-level declarations of every value kind.
431fn root_fragment() -> KtFile {
432 KtFile::new("")
433 .banner("// Hand-tuned banner for the root package.")
434 .decl(
435 KtProperty::val("LIBRARY_VERSION")
436 .ty(KtType::string())
437 .vis(KtVis::Public)
438 .kdoc("Version this binding was generated against.")
439 .initializer("\"1.9.0\""),
440 )
441 // A keyword modifier rendered between visibility and `val`.
442 .decl(
443 KtProperty::val("PROTOCOL")
444 .ty(KtType::string())
445 .vis(KtVis::Public)
446 .modifier("const")
447 .initializer("\"tcp\""),
448 )
449 // A delegated property: `by <expr>` rather than `= <expr>`.
450 .decl(
451 KtProperty::val("defaultTimeout")
452 .vis(KtVis::Internal)
453 .ty(KtType::cls("java.time.Duration"))
454 .delegate("lazy { Duration.ofSeconds(10) }"),
455 )
456 .decl(
457 KtFun::new("describeAll")
458 .vis(KtVis::Public)
459 // Generic parameter lists are free-form text, so a bound is
460 // written as given — it is not shortened against the imports.
461 .generic("T : io.example.api.Describable")
462 .param(KtParam::new(
463 "items",
464 KtType::generic("List", [KtType::var_("T")]),
465 ))
466 .returns(KtType::string())
467 .expr_body(KtCode::new().line("items.joinToString { it.describe() }")),
468 )
469}Sourcepub fn delegate(self, d: impl Into<String>) -> Self
pub fn delegate(self, d: impl Into<String>) -> Self
Examples found in repository?
examples/showcase.rs (line 454)
431fn root_fragment() -> KtFile {
432 KtFile::new("")
433 .banner("// Hand-tuned banner for the root package.")
434 .decl(
435 KtProperty::val("LIBRARY_VERSION")
436 .ty(KtType::string())
437 .vis(KtVis::Public)
438 .kdoc("Version this binding was generated against.")
439 .initializer("\"1.9.0\""),
440 )
441 // A keyword modifier rendered between visibility and `val`.
442 .decl(
443 KtProperty::val("PROTOCOL")
444 .ty(KtType::string())
445 .vis(KtVis::Public)
446 .modifier("const")
447 .initializer("\"tcp\""),
448 )
449 // A delegated property: `by <expr>` rather than `= <expr>`.
450 .decl(
451 KtProperty::val("defaultTimeout")
452 .vis(KtVis::Internal)
453 .ty(KtType::cls("java.time.Duration"))
454 .delegate("lazy { Duration.ofSeconds(10) }"),
455 )
456 .decl(
457 KtFun::new("describeAll")
458 .vis(KtVis::Public)
459 // Generic parameter lists are free-form text, so a bound is
460 // written as given — it is not shortened against the imports.
461 .generic("T : io.example.api.Describable")
462 .param(KtParam::new(
463 "items",
464 KtType::generic("List", [KtType::var_("T")]),
465 ))
466 .returns(KtType::string())
467 .expr_body(KtCode::new().line("items.joinToString { it.describe() }")),
468 )
469}Sourcepub fn vis(self, v: KtVis) -> Self
pub fn vis(self, v: KtVis) -> Self
Examples found in repository?
examples/showcase.rs (line 175)
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}
428
429/// A file in the default (root) package, exercising a banner override and
430/// top-level declarations of every value kind.
431fn root_fragment() -> KtFile {
432 KtFile::new("")
433 .banner("// Hand-tuned banner for the root package.")
434 .decl(
435 KtProperty::val("LIBRARY_VERSION")
436 .ty(KtType::string())
437 .vis(KtVis::Public)
438 .kdoc("Version this binding was generated against.")
439 .initializer("\"1.9.0\""),
440 )
441 // A keyword modifier rendered between visibility and `val`.
442 .decl(
443 KtProperty::val("PROTOCOL")
444 .ty(KtType::string())
445 .vis(KtVis::Public)
446 .modifier("const")
447 .initializer("\"tcp\""),
448 )
449 // A delegated property: `by <expr>` rather than `= <expr>`.
450 .decl(
451 KtProperty::val("defaultTimeout")
452 .vis(KtVis::Internal)
453 .ty(KtType::cls("java.time.Duration"))
454 .delegate("lazy { Duration.ofSeconds(10) }"),
455 )
456 .decl(
457 KtFun::new("describeAll")
458 .vis(KtVis::Public)
459 // Generic parameter lists are free-form text, so a bound is
460 // written as given — it is not shortened against the imports.
461 .generic("T : io.example.api.Describable")
462 .param(KtParam::new(
463 "items",
464 KtType::generic("List", [KtType::var_("T")]),
465 ))
466 .returns(KtType::string())
467 .expr_body(KtCode::new().line("items.joinToString { it.describe() }")),
468 )
469}Sourcepub fn annotation(self, a: impl Into<String>) -> Self
pub fn annotation(self, a: impl Into<String>) -> Self
Examples found in repository?
examples/showcase.rs (line 176)
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 modifier(self, m: impl Into<String>) -> Self
pub fn modifier(self, m: impl Into<String>) -> Self
Examples found in repository?
examples/showcase.rs (line 446)
431fn root_fragment() -> KtFile {
432 KtFile::new("")
433 .banner("// Hand-tuned banner for the root package.")
434 .decl(
435 KtProperty::val("LIBRARY_VERSION")
436 .ty(KtType::string())
437 .vis(KtVis::Public)
438 .kdoc("Version this binding was generated against.")
439 .initializer("\"1.9.0\""),
440 )
441 // A keyword modifier rendered between visibility and `val`.
442 .decl(
443 KtProperty::val("PROTOCOL")
444 .ty(KtType::string())
445 .vis(KtVis::Public)
446 .modifier("const")
447 .initializer("\"tcp\""),
448 )
449 // A delegated property: `by <expr>` rather than `= <expr>`.
450 .decl(
451 KtProperty::val("defaultTimeout")
452 .vis(KtVis::Internal)
453 .ty(KtType::cls("java.time.Duration"))
454 .delegate("lazy { Duration.ofSeconds(10) }"),
455 )
456 .decl(
457 KtFun::new("describeAll")
458 .vis(KtVis::Public)
459 // Generic parameter lists are free-form text, so a bound is
460 // written as given — it is not shortened against the imports.
461 .generic("T : io.example.api.Describable")
462 .param(KtParam::new(
463 "items",
464 KtType::generic("List", [KtType::var_("T")]),
465 ))
466 .returns(KtType::string())
467 .expr_body(KtCode::new().line("items.joinToString { it.describe() }")),
468 )
469}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 177)
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}
428
429/// A file in the default (root) package, exercising a banner override and
430/// top-level declarations of every value kind.
431fn root_fragment() -> KtFile {
432 KtFile::new("")
433 .banner("// Hand-tuned banner for the root package.")
434 .decl(
435 KtProperty::val("LIBRARY_VERSION")
436 .ty(KtType::string())
437 .vis(KtVis::Public)
438 .kdoc("Version this binding was generated against.")
439 .initializer("\"1.9.0\""),
440 )
441 // A keyword modifier rendered between visibility and `val`.
442 .decl(
443 KtProperty::val("PROTOCOL")
444 .ty(KtType::string())
445 .vis(KtVis::Public)
446 .modifier("const")
447 .initializer("\"tcp\""),
448 )
449 // A delegated property: `by <expr>` rather than `= <expr>`.
450 .decl(
451 KtProperty::val("defaultTimeout")
452 .vis(KtVis::Internal)
453 .ty(KtType::cls("java.time.Duration"))
454 .delegate("lazy { Duration.ofSeconds(10) }"),
455 )
456 .decl(
457 KtFun::new("describeAll")
458 .vis(KtVis::Public)
459 // Generic parameter lists are free-form text, so a bound is
460 // written as given — it is not shortened against the imports.
461 .generic("T : io.example.api.Describable")
462 .param(KtParam::new(
463 "items",
464 KtType::generic("List", [KtType::var_("T")]),
465 ))
466 .returns(KtType::string())
467 .expr_body(KtCode::new().line("items.joinToString { it.describe() }")),
468 )
469}Sourcepub fn accessors(self, c: KtCode) -> Self
pub fn accessors(self, c: KtCode) -> Self
Examples found in repository?
examples/showcase.rs (line 184)
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 KtProperty
impl Clone for KtProperty
Source§fn clone(&self) -> KtProperty
fn clone(&self) -> KtProperty
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 KtProperty
impl Debug for KtProperty
Source§impl From<KtProperty> for KtDecl
impl From<KtProperty> for KtDecl
Source§fn from(p: KtProperty) -> Self
fn from(p: KtProperty) -> Self
Converts to this type from the input type.
Auto Trait Implementations§
impl Freeze for KtProperty
impl RefUnwindSafe for KtProperty
impl Send for KtProperty
impl Sync for KtProperty
impl Unpin for KtProperty
impl UnsafeUnpin for KtProperty
impl UnwindSafe for KtProperty
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