pub enum KtType {
Named {
fqn: String,
args: Vec<KtType>,
nullable: bool,
},
Function {
params: Vec<(String, KtType)>,
ret: Box<KtType>,
nullable: bool,
},
}Expand description
A Kotlin type reference.
Variants§
Named
A named type: builtin (Int), type variable (R), or class FQN
(io.zenoh.jni.ZKeyExpr), optionally generic (List<T>).
Function
A function type with named parameters:
(je: String?, message: String) -> Unit.
Implementations§
Source§impl KtType
impl KtType
pub const UNIT: &'static str = "Unit"
Sourcepub fn cls(fqn: impl Into<String>) -> Self
pub fn cls(fqn: impl Into<String>) -> Self
A named type (builtin, type variable, or class FQN).
Examples found in repository?
61fn types_fragment() -> KtFile {
62 // `enum class` with a primary constructor its entries call, plus a named
63 // companion object holding a factory.
64 let priority = KtClass::enum_("Priority")
65 .vis(KtVis::Public)
66 .kdoc("Delivery priority.\n\nMirrors the native `z_priority_t`.")
67 .ctor_param(
68 KtCtorParam::new("code", KtType::int())
69 .val()
70 .vis(KtVis::Public),
71 )
72 .entry(KtEnumEntry::with_args("REAL_TIME", "1"))
73 .entry(KtEnumEntry::with_args("INTERACTIVE", "4"))
74 .entry(KtEnumEntry::with_args("DATA", "5"))
75 .companion(
76 KtCompanion::named("Codes")
77 .vis(KtVis::Public)
78 .kdoc("Lookup helpers keyed by the native code.")
79 .member(
80 KtFun::new("fromInt")
81 .vis(KtVis::Public)
82 .annotation("JvmStatic")
83 .param(KtParam::new("value", KtType::int()))
84 .returns(KtType::cls("Priority"))
85 .body(
86 KtCode::new()
87 .blk("return when (value) {", |c| {
88 c.line("1 -> REAL_TIME")
89 .line("4 -> INTERACTIVE")
90 .line("5 -> DATA")
91 .line("else -> throw IllegalArgumentException(\"bad priority: $value\")")
92 }),
93 ),
94 ),
95 );
96
97 // `@JvmInline value class` — exactly one read-only property.
98 let zid = KtClass::value(
99 "ZenohId",
100 KtCtorParam::new("bytes", KtType::byte_array())
101 .val()
102 .vis(KtVis::Public),
103 )
104 .vis(KtVis::Public)
105 .kdoc("A 16-byte peer identifier, carried by value.");
106
107 // `data class` — every constructor parameter is a property.
108 let sample = KtClass::data(
109 "Sample",
110 KtCtorParam::new("keyExpr", KtType::string())
111 .val()
112 .vis(KtVis::Public),
113 )
114 .vis(KtVis::Public)
115 .ctor_param(
116 KtCtorParam::new("payload", KtType::byte_array())
117 .val()
118 .vis(KtVis::Public),
119 )
120 .ctor_param(
121 KtCtorParam::new("priority", KtType::cls("Priority"))
122 .val()
123 .vis(KtVis::Public)
124 .default("Priority.DATA"),
125 )
126 .ctor_param(
127 KtCtorParam::new("attachment", KtType::byte_array().nullable())
128 .var()
129 .vis(KtVis::Public)
130 .annotation("JvmField")
131 .default("null"),
132 );
133
134 // A `sealed interface` whose alternatives nest inside it: a `data class`
135 // with a payload and a `data object` without one.
136 let reply = KtClass::sealed_interface("Reply")
137 .vis(KtVis::Public)
138 .kdoc("Either a sample or the end of the stream.")
139 .member(
140 KtClass::data(
141 "Value",
142 KtCtorParam::new("sample", KtType::cls("Sample"))
143 .val()
144 .vis(KtVis::Public),
145 )
146 .vis(KtVis::Public)
147 .implements(KtType::cls("Reply")),
148 )
149 .member(
150 KtClass::data_object("Done")
151 .vis(KtVis::Public)
152 .implements(KtType::cls("Reply")),
153 );
154
155 KtFile::new("io.example.api")
156 .decl(priority)
157 .decl(zid)
158 .decl(sample)
159 .decl(reply)
160}
161
162/// The handle surface: an abstract base, a concrete subclass, an interface,
163/// a `fun interface`, and a type alias.
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}More examples
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}
171
172/// The same model, adopted the way a generator that already produces output
173/// would: every check a warning, so nothing is blocked while the backlog is
174/// worked through.
175fn merge_files_warning() -> (Vec<KtFile>, Vec<kotlin_codegen::Diagnostic>) {
176 kotlin_codegen::merge_files_with(broken_files(), &ValidationPolicy::warn_all())
177 .expect("warnings never stop generation")
178}
179
180/// Shapes that are not merely *detected* — they cannot be constructed. The
181/// builder rejects them, so no invalid value ever reaches the renderer.
182fn refused_shapes() -> Vec<(&'static str, String)> {
183 vec![
184 (
185 "object Foo(x: Int) — an object has no primary constructor",
186 refused(|| {
187 KtClass::object_("Foo").ctor_param(KtCtorParam::new("x", KtType::int()));
188 }),
189 ),
190 (
191 "data class Foo(x: Int) — a data class parameter must be a property",
192 refused(|| {
193 KtClass::data("Foo", KtCtorParam::new("x", KtType::int()));
194 }),
195 ),
196 (
197 "value class Foo(var x: Long) — a value class wraps one read-only property",
198 refused(|| {
199 KtClass::value("Foo", KtCtorParam::new("x", KtType::long()).var());
200 }),
201 ),
202 (
203 "class A : B(x), C(y) — Kotlin constructs at most one superclass",
204 refused(|| {
205 KtClass::class_("A")
206 .extends(KtType::cls("B"), Some("x"))
207 .extends(KtType::cls("C"), Some("y"));
208 }),
209 ),
210 (
211 "external fun f() { … } — `external` is a body kind, not a modifier",
212 refused(|| {
213 KtFun::new("f").modifier("external");
214 }),
215 ),
216 (
217 "enum entry on a non-enum class",
218 refused(|| {
219 KtClass::class_("C").entry(KtEnumEntry::new("A"));
220 }),
221 ),
222 (
223 "companion object with an empty name",
224 refused(|| {
225 KtCompanion::named("");
226 }),
227 ),
228 ]
229}Sourcepub fn generic(
fqn: impl Into<String>,
args: impl IntoIterator<Item = KtType>,
) -> Self
pub fn generic( fqn: impl Into<String>, args: impl IntoIterator<Item = KtType>, ) -> Self
A generic named type, e.g. generic("List", [cls("io.x.Y")]).
Examples found in repository?
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 lambda(
params: impl IntoIterator<Item = (String, KtType)>,
ret: KtType,
) -> Self
pub fn lambda( params: impl IntoIterator<Item = (String, KtType)>, ret: KtType, ) -> Self
A function type with named parameters.
Examples found in repository?
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 unit() -> Self
pub fn unit() -> Self
Examples found in repository?
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 int() -> Self
pub fn int() -> Self
Examples found in repository?
61fn types_fragment() -> KtFile {
62 // `enum class` with a primary constructor its entries call, plus a named
63 // companion object holding a factory.
64 let priority = KtClass::enum_("Priority")
65 .vis(KtVis::Public)
66 .kdoc("Delivery priority.\n\nMirrors the native `z_priority_t`.")
67 .ctor_param(
68 KtCtorParam::new("code", KtType::int())
69 .val()
70 .vis(KtVis::Public),
71 )
72 .entry(KtEnumEntry::with_args("REAL_TIME", "1"))
73 .entry(KtEnumEntry::with_args("INTERACTIVE", "4"))
74 .entry(KtEnumEntry::with_args("DATA", "5"))
75 .companion(
76 KtCompanion::named("Codes")
77 .vis(KtVis::Public)
78 .kdoc("Lookup helpers keyed by the native code.")
79 .member(
80 KtFun::new("fromInt")
81 .vis(KtVis::Public)
82 .annotation("JvmStatic")
83 .param(KtParam::new("value", KtType::int()))
84 .returns(KtType::cls("Priority"))
85 .body(
86 KtCode::new()
87 .blk("return when (value) {", |c| {
88 c.line("1 -> REAL_TIME")
89 .line("4 -> INTERACTIVE")
90 .line("5 -> DATA")
91 .line("else -> throw IllegalArgumentException(\"bad priority: $value\")")
92 }),
93 ),
94 ),
95 );
96
97 // `@JvmInline value class` — exactly one read-only property.
98 let zid = KtClass::value(
99 "ZenohId",
100 KtCtorParam::new("bytes", KtType::byte_array())
101 .val()
102 .vis(KtVis::Public),
103 )
104 .vis(KtVis::Public)
105 .kdoc("A 16-byte peer identifier, carried by value.");
106
107 // `data class` — every constructor parameter is a property.
108 let sample = KtClass::data(
109 "Sample",
110 KtCtorParam::new("keyExpr", KtType::string())
111 .val()
112 .vis(KtVis::Public),
113 )
114 .vis(KtVis::Public)
115 .ctor_param(
116 KtCtorParam::new("payload", KtType::byte_array())
117 .val()
118 .vis(KtVis::Public),
119 )
120 .ctor_param(
121 KtCtorParam::new("priority", KtType::cls("Priority"))
122 .val()
123 .vis(KtVis::Public)
124 .default("Priority.DATA"),
125 )
126 .ctor_param(
127 KtCtorParam::new("attachment", KtType::byte_array().nullable())
128 .var()
129 .vis(KtVis::Public)
130 .annotation("JvmField")
131 .default("null"),
132 );
133
134 // A `sealed interface` whose alternatives nest inside it: a `data class`
135 // with a payload and a `data object` without one.
136 let reply = KtClass::sealed_interface("Reply")
137 .vis(KtVis::Public)
138 .kdoc("Either a sample or the end of the stream.")
139 .member(
140 KtClass::data(
141 "Value",
142 KtCtorParam::new("sample", KtType::cls("Sample"))
143 .val()
144 .vis(KtVis::Public),
145 )
146 .vis(KtVis::Public)
147 .implements(KtType::cls("Reply")),
148 )
149 .member(
150 KtClass::data_object("Done")
151 .vis(KtVis::Public)
152 .implements(KtType::cls("Reply")),
153 );
154
155 KtFile::new("io.example.api")
156 .decl(priority)
157 .decl(zid)
158 .decl(sample)
159 .decl(reply)
160}More examples
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}
171
172/// The same model, adopted the way a generator that already produces output
173/// would: every check a warning, so nothing is blocked while the backlog is
174/// worked through.
175fn merge_files_warning() -> (Vec<KtFile>, Vec<kotlin_codegen::Diagnostic>) {
176 kotlin_codegen::merge_files_with(broken_files(), &ValidationPolicy::warn_all())
177 .expect("warnings never stop generation")
178}
179
180/// Shapes that are not merely *detected* — they cannot be constructed. The
181/// builder rejects them, so no invalid value ever reaches the renderer.
182fn refused_shapes() -> Vec<(&'static str, String)> {
183 vec![
184 (
185 "object Foo(x: Int) — an object has no primary constructor",
186 refused(|| {
187 KtClass::object_("Foo").ctor_param(KtCtorParam::new("x", KtType::int()));
188 }),
189 ),
190 (
191 "data class Foo(x: Int) — a data class parameter must be a property",
192 refused(|| {
193 KtClass::data("Foo", KtCtorParam::new("x", KtType::int()));
194 }),
195 ),
196 (
197 "value class Foo(var x: Long) — a value class wraps one read-only property",
198 refused(|| {
199 KtClass::value("Foo", KtCtorParam::new("x", KtType::long()).var());
200 }),
201 ),
202 (
203 "class A : B(x), C(y) — Kotlin constructs at most one superclass",
204 refused(|| {
205 KtClass::class_("A")
206 .extends(KtType::cls("B"), Some("x"))
207 .extends(KtType::cls("C"), Some("y"));
208 }),
209 ),
210 (
211 "external fun f() { … } — `external` is a body kind, not a modifier",
212 refused(|| {
213 KtFun::new("f").modifier("external");
214 }),
215 ),
216 (
217 "enum entry on a non-enum class",
218 refused(|| {
219 KtClass::class_("C").entry(KtEnumEntry::new("A"));
220 }),
221 ),
222 (
223 "companion object with an empty name",
224 refused(|| {
225 KtCompanion::named("");
226 }),
227 ),
228 ]
229}Sourcepub fn long() -> Self
pub fn long() -> Self
Examples found in repository?
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}
171
172/// The same model, adopted the way a generator that already produces output
173/// would: every check a warning, so nothing is blocked while the backlog is
174/// worked through.
175fn merge_files_warning() -> (Vec<KtFile>, Vec<kotlin_codegen::Diagnostic>) {
176 kotlin_codegen::merge_files_with(broken_files(), &ValidationPolicy::warn_all())
177 .expect("warnings never stop generation")
178}
179
180/// Shapes that are not merely *detected* — they cannot be constructed. The
181/// builder rejects them, so no invalid value ever reaches the renderer.
182fn refused_shapes() -> Vec<(&'static str, String)> {
183 vec![
184 (
185 "object Foo(x: Int) — an object has no primary constructor",
186 refused(|| {
187 KtClass::object_("Foo").ctor_param(KtCtorParam::new("x", KtType::int()));
188 }),
189 ),
190 (
191 "data class Foo(x: Int) — a data class parameter must be a property",
192 refused(|| {
193 KtClass::data("Foo", KtCtorParam::new("x", KtType::int()));
194 }),
195 ),
196 (
197 "value class Foo(var x: Long) — a value class wraps one read-only property",
198 refused(|| {
199 KtClass::value("Foo", KtCtorParam::new("x", KtType::long()).var());
200 }),
201 ),
202 (
203 "class A : B(x), C(y) — Kotlin constructs at most one superclass",
204 refused(|| {
205 KtClass::class_("A")
206 .extends(KtType::cls("B"), Some("x"))
207 .extends(KtType::cls("C"), Some("y"));
208 }),
209 ),
210 (
211 "external fun f() { … } — `external` is a body kind, not a modifier",
212 refused(|| {
213 KtFun::new("f").modifier("external");
214 }),
215 ),
216 (
217 "enum entry on a non-enum class",
218 refused(|| {
219 KtClass::class_("C").entry(KtEnumEntry::new("A"));
220 }),
221 ),
222 (
223 "companion object with an empty name",
224 refused(|| {
225 KtCompanion::named("");
226 }),
227 ),
228 ]
229}More examples
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 boolean() -> Self
pub fn boolean() -> Self
Examples found in repository?
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
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 string() -> Self
pub fn string() -> Self
Examples found in repository?
61fn types_fragment() -> KtFile {
62 // `enum class` with a primary constructor its entries call, plus a named
63 // companion object holding a factory.
64 let priority = KtClass::enum_("Priority")
65 .vis(KtVis::Public)
66 .kdoc("Delivery priority.\n\nMirrors the native `z_priority_t`.")
67 .ctor_param(
68 KtCtorParam::new("code", KtType::int())
69 .val()
70 .vis(KtVis::Public),
71 )
72 .entry(KtEnumEntry::with_args("REAL_TIME", "1"))
73 .entry(KtEnumEntry::with_args("INTERACTIVE", "4"))
74 .entry(KtEnumEntry::with_args("DATA", "5"))
75 .companion(
76 KtCompanion::named("Codes")
77 .vis(KtVis::Public)
78 .kdoc("Lookup helpers keyed by the native code.")
79 .member(
80 KtFun::new("fromInt")
81 .vis(KtVis::Public)
82 .annotation("JvmStatic")
83 .param(KtParam::new("value", KtType::int()))
84 .returns(KtType::cls("Priority"))
85 .body(
86 KtCode::new()
87 .blk("return when (value) {", |c| {
88 c.line("1 -> REAL_TIME")
89 .line("4 -> INTERACTIVE")
90 .line("5 -> DATA")
91 .line("else -> throw IllegalArgumentException(\"bad priority: $value\")")
92 }),
93 ),
94 ),
95 );
96
97 // `@JvmInline value class` — exactly one read-only property.
98 let zid = KtClass::value(
99 "ZenohId",
100 KtCtorParam::new("bytes", KtType::byte_array())
101 .val()
102 .vis(KtVis::Public),
103 )
104 .vis(KtVis::Public)
105 .kdoc("A 16-byte peer identifier, carried by value.");
106
107 // `data class` — every constructor parameter is a property.
108 let sample = KtClass::data(
109 "Sample",
110 KtCtorParam::new("keyExpr", KtType::string())
111 .val()
112 .vis(KtVis::Public),
113 )
114 .vis(KtVis::Public)
115 .ctor_param(
116 KtCtorParam::new("payload", KtType::byte_array())
117 .val()
118 .vis(KtVis::Public),
119 )
120 .ctor_param(
121 KtCtorParam::new("priority", KtType::cls("Priority"))
122 .val()
123 .vis(KtVis::Public)
124 .default("Priority.DATA"),
125 )
126 .ctor_param(
127 KtCtorParam::new("attachment", KtType::byte_array().nullable())
128 .var()
129 .vis(KtVis::Public)
130 .annotation("JvmField")
131 .default("null"),
132 );
133
134 // A `sealed interface` whose alternatives nest inside it: a `data class`
135 // with a payload and a `data object` without one.
136 let reply = KtClass::sealed_interface("Reply")
137 .vis(KtVis::Public)
138 .kdoc("Either a sample or the end of the stream.")
139 .member(
140 KtClass::data(
141 "Value",
142 KtCtorParam::new("sample", KtType::cls("Sample"))
143 .val()
144 .vis(KtVis::Public),
145 )
146 .vis(KtVis::Public)
147 .implements(KtType::cls("Reply")),
148 )
149 .member(
150 KtClass::data_object("Done")
151 .vis(KtVis::Public)
152 .implements(KtType::cls("Reply")),
153 );
154
155 KtFile::new("io.example.api")
156 .decl(priority)
157 .decl(zid)
158 .decl(sample)
159 .decl(reply)
160}
161
162/// The handle surface: an abstract base, a concrete subclass, an interface,
163/// a `fun interface`, and a type alias.
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}More examples
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}Sourcepub fn byte_array() -> Self
pub fn byte_array() -> Self
Examples found in repository?
61fn types_fragment() -> KtFile {
62 // `enum class` with a primary constructor its entries call, plus a named
63 // companion object holding a factory.
64 let priority = KtClass::enum_("Priority")
65 .vis(KtVis::Public)
66 .kdoc("Delivery priority.\n\nMirrors the native `z_priority_t`.")
67 .ctor_param(
68 KtCtorParam::new("code", KtType::int())
69 .val()
70 .vis(KtVis::Public),
71 )
72 .entry(KtEnumEntry::with_args("REAL_TIME", "1"))
73 .entry(KtEnumEntry::with_args("INTERACTIVE", "4"))
74 .entry(KtEnumEntry::with_args("DATA", "5"))
75 .companion(
76 KtCompanion::named("Codes")
77 .vis(KtVis::Public)
78 .kdoc("Lookup helpers keyed by the native code.")
79 .member(
80 KtFun::new("fromInt")
81 .vis(KtVis::Public)
82 .annotation("JvmStatic")
83 .param(KtParam::new("value", KtType::int()))
84 .returns(KtType::cls("Priority"))
85 .body(
86 KtCode::new()
87 .blk("return when (value) {", |c| {
88 c.line("1 -> REAL_TIME")
89 .line("4 -> INTERACTIVE")
90 .line("5 -> DATA")
91 .line("else -> throw IllegalArgumentException(\"bad priority: $value\")")
92 }),
93 ),
94 ),
95 );
96
97 // `@JvmInline value class` — exactly one read-only property.
98 let zid = KtClass::value(
99 "ZenohId",
100 KtCtorParam::new("bytes", KtType::byte_array())
101 .val()
102 .vis(KtVis::Public),
103 )
104 .vis(KtVis::Public)
105 .kdoc("A 16-byte peer identifier, carried by value.");
106
107 // `data class` — every constructor parameter is a property.
108 let sample = KtClass::data(
109 "Sample",
110 KtCtorParam::new("keyExpr", KtType::string())
111 .val()
112 .vis(KtVis::Public),
113 )
114 .vis(KtVis::Public)
115 .ctor_param(
116 KtCtorParam::new("payload", KtType::byte_array())
117 .val()
118 .vis(KtVis::Public),
119 )
120 .ctor_param(
121 KtCtorParam::new("priority", KtType::cls("Priority"))
122 .val()
123 .vis(KtVis::Public)
124 .default("Priority.DATA"),
125 )
126 .ctor_param(
127 KtCtorParam::new("attachment", KtType::byte_array().nullable())
128 .var()
129 .vis(KtVis::Public)
130 .annotation("JvmField")
131 .default("null"),
132 );
133
134 // A `sealed interface` whose alternatives nest inside it: a `data class`
135 // with a payload and a `data object` without one.
136 let reply = KtClass::sealed_interface("Reply")
137 .vis(KtVis::Public)
138 .kdoc("Either a sample or the end of the stream.")
139 .member(
140 KtClass::data(
141 "Value",
142 KtCtorParam::new("sample", KtType::cls("Sample"))
143 .val()
144 .vis(KtVis::Public),
145 )
146 .vis(KtVis::Public)
147 .implements(KtType::cls("Reply")),
148 )
149 .member(
150 KtClass::data_object("Done")
151 .vis(KtVis::Public)
152 .implements(KtType::cls("Reply")),
153 );
154
155 KtFile::new("io.example.api")
156 .decl(priority)
157 .decl(zid)
158 .decl(sample)
159 .decl(reply)
160}
161
162/// The handle surface: an abstract base, a concrete subclass, an interface,
163/// a `fun interface`, and a type alias.
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}pub fn any() -> Self
Sourcepub fn var_(name: impl Into<String>) -> Self
pub fn var_(name: impl Into<String>) -> Self
A bare type variable (R, A) — renders verbatim, never imported.
Examples found in repository?
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_r() -> Self
pub fn var_r() -> Self
Shorthand for the ubiquitous R type variable.
Examples found in repository?
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 nullable(self) -> Self
pub fn nullable(self) -> Self
This type made nullable (T?).
Examples found in repository?
61fn types_fragment() -> KtFile {
62 // `enum class` with a primary constructor its entries call, plus a named
63 // companion object holding a factory.
64 let priority = KtClass::enum_("Priority")
65 .vis(KtVis::Public)
66 .kdoc("Delivery priority.\n\nMirrors the native `z_priority_t`.")
67 .ctor_param(
68 KtCtorParam::new("code", KtType::int())
69 .val()
70 .vis(KtVis::Public),
71 )
72 .entry(KtEnumEntry::with_args("REAL_TIME", "1"))
73 .entry(KtEnumEntry::with_args("INTERACTIVE", "4"))
74 .entry(KtEnumEntry::with_args("DATA", "5"))
75 .companion(
76 KtCompanion::named("Codes")
77 .vis(KtVis::Public)
78 .kdoc("Lookup helpers keyed by the native code.")
79 .member(
80 KtFun::new("fromInt")
81 .vis(KtVis::Public)
82 .annotation("JvmStatic")
83 .param(KtParam::new("value", KtType::int()))
84 .returns(KtType::cls("Priority"))
85 .body(
86 KtCode::new()
87 .blk("return when (value) {", |c| {
88 c.line("1 -> REAL_TIME")
89 .line("4 -> INTERACTIVE")
90 .line("5 -> DATA")
91 .line("else -> throw IllegalArgumentException(\"bad priority: $value\")")
92 }),
93 ),
94 ),
95 );
96
97 // `@JvmInline value class` — exactly one read-only property.
98 let zid = KtClass::value(
99 "ZenohId",
100 KtCtorParam::new("bytes", KtType::byte_array())
101 .val()
102 .vis(KtVis::Public),
103 )
104 .vis(KtVis::Public)
105 .kdoc("A 16-byte peer identifier, carried by value.");
106
107 // `data class` — every constructor parameter is a property.
108 let sample = KtClass::data(
109 "Sample",
110 KtCtorParam::new("keyExpr", KtType::string())
111 .val()
112 .vis(KtVis::Public),
113 )
114 .vis(KtVis::Public)
115 .ctor_param(
116 KtCtorParam::new("payload", KtType::byte_array())
117 .val()
118 .vis(KtVis::Public),
119 )
120 .ctor_param(
121 KtCtorParam::new("priority", KtType::cls("Priority"))
122 .val()
123 .vis(KtVis::Public)
124 .default("Priority.DATA"),
125 )
126 .ctor_param(
127 KtCtorParam::new("attachment", KtType::byte_array().nullable())
128 .var()
129 .vis(KtVis::Public)
130 .annotation("JvmField")
131 .default("null"),
132 );
133
134 // A `sealed interface` whose alternatives nest inside it: a `data class`
135 // with a payload and a `data object` without one.
136 let reply = KtClass::sealed_interface("Reply")
137 .vis(KtVis::Public)
138 .kdoc("Either a sample or the end of the stream.")
139 .member(
140 KtClass::data(
141 "Value",
142 KtCtorParam::new("sample", KtType::cls("Sample"))
143 .val()
144 .vis(KtVis::Public),
145 )
146 .vis(KtVis::Public)
147 .implements(KtType::cls("Reply")),
148 )
149 .member(
150 KtClass::data_object("Done")
151 .vis(KtVis::Public)
152 .implements(KtType::cls("Reply")),
153 );
154
155 KtFile::new("io.example.api")
156 .decl(priority)
157 .decl(zid)
158 .decl(sample)
159 .decl(reply)
160}Sourcepub fn is_nullable(&self) -> bool
pub fn is_nullable(&self) -> bool
Whether this type is nullable (T? / ((…) -> …)?).
Sourcepub fn leaf_name(&self) -> Option<&str>
pub fn leaf_name(&self) -> Option<&str>
The (possibly dotted) name of a non-generic named type — None for
function types and generics. This is the FQN-or-short-name string a
leaf was constructed from.
Sourcepub fn simple_name(&self) -> Option<&str>
pub fn simple_name(&self) -> Option<&str>
The simple (dot-free) name of a named type: last FQN segment, generic
arguments ignored. None for function types.
Sourcepub fn render_receiver(&self, imports: &mut ImportSet) -> String
pub fn render_receiver(&self, imports: &mut ImportSet) -> String
Render in extension-receiver position — fun <this>.name().
A function type needs parentheses there, or the . binds to its return
type instead: fun ((Int) -> String).ext(), never
fun (Int) -> String.ext(). A nullable one is already parenthesized by
Self::render, so it is left alone.
use kotlin_codegen::{ImportSet, KtType};
let mut imports = ImportSet::new("io.p");
let f = KtType::lambda([("x".to_string(), KtType::int())], KtType::string());
assert_eq!(f.render_receiver(&mut imports), "((x: Int) -> String)");
assert_eq!(KtType::string().render_receiver(&mut imports), "String");Trait Implementations§
Source§impl Display for KtType
Renders the type with names exactly as constructed (FQNs stay fully
qualified — no import shortening). For diagnostics and any context
without an ImportSet.
impl Display for KtType
Renders the type with names exactly as constructed (FQNs stay fully
qualified — no import shortening). For diagnostics and any context
without an ImportSet.