Skip to main content

KtCompanion

Struct KtCompanion 

Source
pub struct KtCompanion {
    pub name: Option<String>,
    pub vis: KtVis,
    pub kdoc: Option<String>,
    pub annotations: Vec<String>,
    pub supertypes: KtSupertypes,
    pub members: Vec<KtDecl>,
}
Expand description

A companion object.

Its own type rather than a KtClassKind variant, because a companion is only meaningful inside a class body: reachable solely as KtClass::companion, it cannot be built as a top-level declaration.

A companion has no primary constructor, so — unlike the KtClass it used to borrow its shape from — there is nowhere to put constructor parameters.

There is no impl Into<KtDecl>, so a companion cannot reach a declaration position at all:

use kotlin_codegen::{KtCompanion, KtFile};
// `companion object` is meaningless at file level — and unbuildable.
let _ = KtFile::new("io.p").decl(KtCompanion::new());

Fields§

§name: Option<String>

None renders the anonymous form companion object { … } (Kotlin names it Companion implicitly). Some(n) renders companion object n { … }, which an emitter needs when the implicit Companion would collide with a sibling declaration.

§vis: KtVis§kdoc: Option<String>§annotations: Vec<String>§supertypes: KtSupertypes

What the companion extends and implements.

§members: Vec<KtDecl>

Implementations§

Source§

impl KtCompanion

Source

pub fn new() -> Self

An anonymous companion object.

Examples found in repository?
examples/showcase.rs (line 274)
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}
Source

pub fn named(name: impl Into<String>) -> Self

A named companion object Factory { … }.

§Panics

On an empty name, which would render as companion object with a dangling space. KtCompanion::new is the anonymous form.

Examples found in repository?
examples/showcase.rs (line 76)
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
Hide additional examples
examples/invalid.rs (line 155)
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}
Source

pub fn vis(self, v: KtVis) -> Self

Examples found in repository?
examples/showcase.rs (line 77)
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}
Source

pub fn kdoc(self, d: impl Into<String>) -> Self

Examples found in repository?
examples/showcase.rs (line 78)
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}
Source

pub fn annotation(self, a: impl Into<String>) -> Self

Source

pub fn extends(self, ty: KtType, args: Option<&str>) -> Self

Set the one superclass this companion extends. Kotlin allows a companion object to extend a class, the same as any other object.

§Panics

If a superclass is already set — see KtClass::extends.

Source

pub fn implements(self, ty: KtType) -> Self

Implement an interface.

Source

pub fn member(self, d: impl Into<KtDecl>) -> Self

Examples found in repository?
examples/showcase.rs (lines 79-94)
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}

Trait Implementations§

Source§

impl Clone for KtCompanion

Source§

fn clone(&self) -> KtCompanion

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for KtCompanion

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for KtCompanion

Source§

fn default() -> KtCompanion

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.