@@ -0,0 +1,1146 @@
1+package soy.iko.opencode.core
3+import com.novi.bincode.BincodeDeserializer
4+import com.novi.bincode.BincodeSerializer
5+import com.novi.serde.Bytes
6+import com.novi.serde.DeserializationError
7+import com.novi.serde.Deserializer
8+import com.novi.serde.Serializer
10+fun <T> List<T>.serialize(
11+ serializer: Serializer,
12+ serializeElement: Serializer.(T) -> Unit,
14+ serializer.serialize_len(size.toLong())
16+ serializer.serializeElement(element)
20+fun <T> Deserializer.deserializeListOf(deserializeElement: (Deserializer) -> T): List<T> {
21+ val length = deserialize_len()
22+ val list = mutableListOf<T>()
23+ repeat(length.toInt()) {
24+ list.add(deserializeElement(this))
29+fun <T> T?.serializeOptionOf(
30+ serializer: Serializer,
31+ serializeElement: Serializer.(T) -> Unit,
34+ serializer.serialize_option_tag(true)
35+ serializer.serializeElement(this)
37+ serializer.serialize_option_tag(false)
41+fun <T> Deserializer.deserializeOptionOf(deserializeElement: (Deserializer) -> T): T? {
42+ val tag = deserialize_option_tag()
44+ deserializeElement(this)
50+sealed interface Effect {
51+ fun serialize(serializer: Serializer)
53+ fun bincodeSerialize(): ByteArray {
54+ val serializer = BincodeSerializer()
55+ serialize(serializer)
56+ return serializer.get_bytes()
60+ val value: soy.iko.opencode.core.RenderOperation,
62+ override fun serialize(serializer: Serializer) {
63+ serializer.increase_container_depth()
64+ serializer.serialize_variant_index(0)
65+ value.serialize(serializer)
66+ serializer.decrease_container_depth()
70+ fun deserialize(deserializer: Deserializer): Render {
71+ deserializer.increase_container_depth()
72+ val value = soy.iko.opencode.core.RenderOperation.deserialize(deserializer)
73+ deserializer.decrease_container_depth()
80+ val value: soy.iko.opencode.core.HttpRequest,
82+ override fun serialize(serializer: Serializer) {
83+ serializer.increase_container_depth()
84+ serializer.serialize_variant_index(1)
85+ value.serialize(serializer)
86+ serializer.decrease_container_depth()
90+ fun deserialize(deserializer: Deserializer): Http {
91+ deserializer.increase_container_depth()
92+ val value = soy.iko.opencode.core.HttpRequest.deserialize(deserializer)
93+ deserializer.decrease_container_depth()
100+ @Throws(DeserializationError::class)
101+ fun deserialize(deserializer: Deserializer): Effect {
102+ val index = deserializer.deserialize_variant_index()
103+ return when (index) {
104+ 0 -> Render.deserialize(deserializer)
105+ 1 -> Http.deserialize(deserializer)
106+ else -> throw DeserializationError("Unknown variant index for Effect: $index")
110+ @Throws(DeserializationError::class)
111+ fun bincodeDeserialize(input: ByteArray?): Effect {
112+ if (input == null) {
113+ throw DeserializationError("Cannot deserialize null array")
115+ val deserializer = BincodeDeserializer(input)
116+ val value = deserialize(deserializer)
117+ if (deserializer.get_buffer_offset() < input.size) {
118+ throw DeserializationError("Some input bytes were not read")
125+sealed interface Event {
126+ fun serialize(serializer: Serializer)
128+ fun bincodeSerialize(): ByteArray {
129+ val serializer = BincodeSerializer()
130+ serialize(serializer)
131+ return serializer.get_bytes()
134+ data object Start: Event {
135+ override fun serialize(serializer: Serializer) {
136+ serializer.increase_container_depth()
137+ serializer.serialize_variant_index(0)
138+ serializer.decrease_container_depth()
141+ fun deserialize(deserializer: Deserializer): Start {
146+ data class ServerUrlChanged(
149+ override fun serialize(serializer: Serializer) {
150+ serializer.increase_container_depth()
151+ serializer.serialize_variant_index(1)
152+ serializer.serialize_str(value)
153+ serializer.decrease_container_depth()
157+ fun deserialize(deserializer: Deserializer): ServerUrlChanged {
158+ deserializer.increase_container_depth()
159+ val value = deserializer.deserialize_str()
160+ deserializer.decrease_container_depth()
161+ return ServerUrlChanged(value)
166+ data class UsernameChanged(
169+ override fun serialize(serializer: Serializer) {
170+ serializer.increase_container_depth()
171+ serializer.serialize_variant_index(2)
172+ serializer.serialize_str(value)
173+ serializer.decrease_container_depth()
177+ fun deserialize(deserializer: Deserializer): UsernameChanged {
178+ deserializer.increase_container_depth()
179+ val value = deserializer.deserialize_str()
180+ deserializer.decrease_container_depth()
181+ return UsernameChanged(value)
186+ data class PasswordChanged(
189+ override fun serialize(serializer: Serializer) {
190+ serializer.increase_container_depth()
191+ serializer.serialize_variant_index(3)
192+ serializer.serialize_str(value)
193+ serializer.decrease_container_depth()
197+ fun deserialize(deserializer: Deserializer): PasswordChanged {
198+ deserializer.increase_container_depth()
199+ val value = deserializer.deserialize_str()
200+ deserializer.decrease_container_depth()
201+ return PasswordChanged(value)
206+ data object Connect: Event {
207+ override fun serialize(serializer: Serializer) {
208+ serializer.increase_container_depth()
209+ serializer.serialize_variant_index(4)
210+ serializer.decrease_container_depth()
213+ fun deserialize(deserializer: Deserializer): Connect {
218+ data object CancelAuth: Event {
219+ override fun serialize(serializer: Serializer) {
220+ serializer.increase_container_depth()
221+ serializer.serialize_variant_index(5)
222+ serializer.decrease_container_depth()
225+ fun deserialize(deserializer: Deserializer): CancelAuth {
230+ data object LoadSessions: Event {
231+ override fun serialize(serializer: Serializer) {
232+ serializer.increase_container_depth()
233+ serializer.serialize_variant_index(6)
234+ serializer.decrease_container_depth()
237+ fun deserialize(deserializer: Deserializer): LoadSessions {
242+ data class SelectSession(
245+ override fun serialize(serializer: Serializer) {
246+ serializer.increase_container_depth()
247+ serializer.serialize_variant_index(7)
248+ serializer.serialize_str(value)
249+ serializer.decrease_container_depth()
253+ fun deserialize(deserializer: Deserializer): SelectSession {
254+ deserializer.increase_container_depth()
255+ val value = deserializer.deserialize_str()
256+ deserializer.decrease_container_depth()
257+ return SelectSession(value)
262+ data object CreateSession: Event {
263+ override fun serialize(serializer: Serializer) {
264+ serializer.increase_container_depth()
265+ serializer.serialize_variant_index(8)
266+ serializer.decrease_container_depth()
269+ fun deserialize(deserializer: Deserializer): CreateSession {
270+ return CreateSession
274+ data class LoadMessages(
277+ override fun serialize(serializer: Serializer) {
278+ serializer.increase_container_depth()
279+ serializer.serialize_variant_index(9)
280+ serializer.serialize_str(value)
281+ serializer.decrease_container_depth()
285+ fun deserialize(deserializer: Deserializer): LoadMessages {
286+ deserializer.increase_container_depth()
287+ val value = deserializer.deserialize_str()
288+ deserializer.decrease_container_depth()
289+ return LoadMessages(value)
294+ data class SendMessage(
297+ override fun serialize(serializer: Serializer) {
298+ serializer.increase_container_depth()
299+ serializer.serialize_variant_index(10)
300+ serializer.serialize_str(value)
301+ serializer.decrease_container_depth()
305+ fun deserialize(deserializer: Deserializer): SendMessage {
306+ deserializer.increase_container_depth()
307+ val value = deserializer.deserialize_str()
308+ deserializer.decrease_container_depth()
309+ return SendMessage(value)
314+ data class EventReceived(
317+ override fun serialize(serializer: Serializer) {
318+ serializer.increase_container_depth()
319+ serializer.serialize_variant_index(11)
320+ serializer.serialize_str(value)
321+ serializer.decrease_container_depth()
325+ fun deserialize(deserializer: Deserializer): EventReceived {
326+ deserializer.increase_container_depth()
327+ val value = deserializer.deserialize_str()
328+ deserializer.decrease_container_depth()
329+ return EventReceived(value)
334+ data class NavigateToChat(
337+ override fun serialize(serializer: Serializer) {
338+ serializer.increase_container_depth()
339+ serializer.serialize_variant_index(12)
340+ serializer.serialize_str(value)
341+ serializer.decrease_container_depth()
345+ fun deserialize(deserializer: Deserializer): NavigateToChat {
346+ deserializer.increase_container_depth()
347+ val value = deserializer.deserialize_str()
348+ deserializer.decrease_container_depth()
349+ return NavigateToChat(value)
354+ data object NavigateToSessions: Event {
355+ override fun serialize(serializer: Serializer) {
356+ serializer.increase_container_depth()
357+ serializer.serialize_variant_index(13)
358+ serializer.decrease_container_depth()
361+ fun deserialize(deserializer: Deserializer): NavigateToSessions {
362+ return NavigateToSessions
366+ data object DismissError: Event {
367+ override fun serialize(serializer: Serializer) {
368+ serializer.increase_container_depth()
369+ serializer.serialize_variant_index(14)
370+ serializer.decrease_container_depth()
373+ fun deserialize(deserializer: Deserializer): DismissError {
379+ @Throws(DeserializationError::class)
380+ fun deserialize(deserializer: Deserializer): Event {
381+ val index = deserializer.deserialize_variant_index()
382+ return when (index) {
383+ 0 -> Start.deserialize(deserializer)
384+ 1 -> ServerUrlChanged.deserialize(deserializer)
385+ 2 -> UsernameChanged.deserialize(deserializer)
386+ 3 -> PasswordChanged.deserialize(deserializer)
387+ 4 -> Connect.deserialize(deserializer)
388+ 5 -> CancelAuth.deserialize(deserializer)
389+ 6 -> LoadSessions.deserialize(deserializer)
390+ 7 -> SelectSession.deserialize(deserializer)
391+ 8 -> CreateSession.deserialize(deserializer)
392+ 9 -> LoadMessages.deserialize(deserializer)
393+ 10 -> SendMessage.deserialize(deserializer)
394+ 11 -> EventReceived.deserialize(deserializer)
395+ 12 -> NavigateToChat.deserialize(deserializer)
396+ 13 -> NavigateToSessions.deserialize(deserializer)
397+ 14 -> DismissError.deserialize(deserializer)
398+ else -> throw DeserializationError("Unknown variant index for Event: $index")
402+ @Throws(DeserializationError::class)
403+ fun bincodeDeserialize(input: ByteArray?): Event {
404+ if (input == null) {
405+ throw DeserializationError("Cannot deserialize null array")
407+ val deserializer = BincodeDeserializer(input)
408+ val value = deserialize(deserializer)
409+ if (deserializer.get_buffer_offset() < input.size) {
410+ throw DeserializationError("Some input bytes were not read")
417+/// An error produced when an HTTP request fails.
419+/// Variants fall into two groups:
421+/// **Transport errors** — generated by the shell when it cannot complete the HTTP
422+/// exchange. These cross the FFI boundary and are serialized in the protocol:
423+/// [`Url`](HttpError::Url), [`Io`](HttpError::Io), [`Timeout`](HttpError::Timeout).
425+/// **Processing errors** — generated on the Rust side after a response arrives.
426+/// These are never serialized or visible to shells:
428+/// - [`Http`](HttpError::Http) — produced by `Response::new()` when the server returns
429+/// a 4xx or 5xx status. At the *protocol* level these arrive as
430+/// [`HttpResult::Ok`](crate::protocol::HttpResult::Ok); `Response::new()` converts
431+/// them here, so app code using `crux_http::Result<Response<T>>` will see them as
432+/// `Err(HttpError::Http { code, .. })`.
433+/// - [`Json`](HttpError::Json) — produced when response body deserialisation fails.
434+sealed interface HttpError {
435+ fun serialize(serializer: Serializer)
437+ fun bincodeSerialize(): ByteArray {
438+ val serializer = BincodeSerializer()
439+ serialize(serializer)
440+ return serializer.get_bytes()
443+ /// The request URL could not be parsed.
447+ override fun serialize(serializer: Serializer) {
448+ serializer.increase_container_depth()
449+ serializer.serialize_variant_index(0)
450+ serializer.serialize_str(value)
451+ serializer.decrease_container_depth()
455+ fun deserialize(deserializer: Deserializer): Url {
456+ deserializer.increase_container_depth()
457+ val value = deserializer.deserialize_str()
458+ deserializer.decrease_container_depth()
464+ /// An IO error prevented the request from completing.
468+ override fun serialize(serializer: Serializer) {
469+ serializer.increase_container_depth()
470+ serializer.serialize_variant_index(1)
471+ serializer.serialize_str(value)
472+ serializer.decrease_container_depth()
476+ fun deserialize(deserializer: Deserializer): Io {
477+ deserializer.increase_container_depth()
478+ val value = deserializer.deserialize_str()
479+ deserializer.decrease_container_depth()
485+ /// The request timed out before a response was received.
486+ data object Timeout: HttpError {
487+ override fun serialize(serializer: Serializer) {
488+ serializer.increase_container_depth()
489+ serializer.serialize_variant_index(2)
490+ serializer.decrease_container_depth()
493+ fun deserialize(deserializer: Deserializer): Timeout {
499+ @Throws(DeserializationError::class)
500+ fun deserialize(deserializer: Deserializer): HttpError {
501+ val index = deserializer.deserialize_variant_index()
502+ return when (index) {
503+ 0 -> Url.deserialize(deserializer)
504+ 1 -> Io.deserialize(deserializer)
505+ 2 -> Timeout.deserialize(deserializer)
506+ else -> throw DeserializationError("Unknown variant index for HttpError: $index")
510+ @Throws(DeserializationError::class)
511+ fun bincodeDeserialize(input: ByteArray?): HttpError {
512+ if (input == null) {
513+ throw DeserializationError("Cannot deserialize null array")
515+ val deserializer = BincodeDeserializer(input)
516+ val value = deserialize(deserializer)
517+ if (deserializer.get_buffer_offset() < input.size) {
518+ throw DeserializationError("Some input bytes were not read")
525+data class HttpHeader(
529+ fun serialize(serializer: Serializer) {
530+ serializer.increase_container_depth()
531+ serializer.serialize_str(name)
532+ serializer.serialize_str(value)
533+ serializer.decrease_container_depth()
536+ fun bincodeSerialize(): ByteArray {
537+ val serializer = BincodeSerializer()
538+ serialize(serializer)
539+ return serializer.get_bytes()
543+ fun deserialize(deserializer: Deserializer): HttpHeader {
544+ deserializer.increase_container_depth()
545+ val name = deserializer.deserialize_str()
546+ val value = deserializer.deserialize_str()
547+ deserializer.decrease_container_depth()
548+ return HttpHeader(name, value)
551+ @Throws(DeserializationError::class)
552+ fun bincodeDeserialize(input: ByteArray?): HttpHeader {
553+ if (input == null) {
554+ throw DeserializationError("Cannot deserialize null array")
556+ val deserializer = BincodeDeserializer(input)
557+ val value = deserialize(deserializer)
558+ if (deserializer.get_buffer_offset() < input.size) {
559+ throw DeserializationError("Some input bytes were not read")
566+/// A raw HTTP request, as sent to the shell over the protocol boundary.
568+/// # No header validation
570+/// All fields are plain strings. Header names and values are carried as-is with no
571+/// validation against the HTTP specification. This is intentional: `HttpRequest` is a
572+/// cross-language data carrier deserialised by Swift, Kotlin, and TypeScript shells;
573+/// Rust's `http`-crate validation rules cannot be enforced on the other side of that
576+/// **Shell authors must not assume that header names or values are well-formed.**
577+/// Pass them to your underlying HTTP client as-is — it will apply its own rules.
579+/// For the ergonomic Rust-side builder that *does* validate header values (and panics
580+/// on invalid input), see [`crate::command::RequestBuilder`].
581+data class HttpRequest(
584+ val headers: List<soy.iko.opencode.core.HttpHeader>,
587+ fun serialize(serializer: Serializer) {
588+ serializer.increase_container_depth()
589+ serializer.serialize_str(method)
590+ serializer.serialize_str(url)
591+ headers.serialize(serializer) {
592+ it.serialize(serializer)
594+ serializer.serialize_bytes(body)
595+ serializer.decrease_container_depth()
598+ fun bincodeSerialize(): ByteArray {
599+ val serializer = BincodeSerializer()
600+ serialize(serializer)
601+ return serializer.get_bytes()
605+ fun deserialize(deserializer: Deserializer): HttpRequest {
606+ deserializer.increase_container_depth()
607+ val method = deserializer.deserialize_str()
608+ val url = deserializer.deserialize_str()
610+ deserializer.deserializeListOf {
611+ soy.iko.opencode.core.HttpHeader.deserialize(deserializer)
613+ val body = deserializer.deserialize_bytes()
614+ deserializer.decrease_container_depth()
615+ return HttpRequest(method, url, headers, body)
618+ @Throws(DeserializationError::class)
619+ fun bincodeDeserialize(input: ByteArray?): HttpRequest {
620+ if (input == null) {
621+ throw DeserializationError("Cannot deserialize null array")
623+ val deserializer = BincodeDeserializer(input)
624+ val value = deserialize(deserializer)
625+ if (deserializer.get_buffer_offset() < input.size) {
626+ throw DeserializationError("Some input bytes were not read")
633+data class HttpResponse(
635+ val headers: List<soy.iko.opencode.core.HttpHeader>,
638+ fun serialize(serializer: Serializer) {
639+ serializer.increase_container_depth()
640+ serializer.serialize_u16(status)
641+ headers.serialize(serializer) {
642+ it.serialize(serializer)
644+ serializer.serialize_bytes(body)
645+ serializer.decrease_container_depth()
648+ fun bincodeSerialize(): ByteArray {
649+ val serializer = BincodeSerializer()
650+ serialize(serializer)
651+ return serializer.get_bytes()
655+ fun deserialize(deserializer: Deserializer): HttpResponse {
656+ deserializer.increase_container_depth()
657+ val status = deserializer.deserialize_u16()
659+ deserializer.deserializeListOf {
660+ soy.iko.opencode.core.HttpHeader.deserialize(deserializer)
662+ val body = deserializer.deserialize_bytes()
663+ deserializer.decrease_container_depth()
664+ return HttpResponse(status, headers, body)
667+ @Throws(DeserializationError::class)
668+ fun bincodeDeserialize(input: ByteArray?): HttpResponse {
669+ if (input == null) {
670+ throw DeserializationError("Cannot deserialize null array")
672+ val deserializer = BincodeDeserializer(input)
673+ val value = deserialize(deserializer)
674+ if (deserializer.get_buffer_offset() < input.size) {
675+ throw DeserializationError("Some input bytes were not read")
682+/// The result of an HTTP request, as returned by the shell over the protocol boundary.
684+/// # Status codes are not errors
686+/// Any completed HTTP exchange — including responses with 4xx or 5xx status codes — is
687+/// returned as [`HttpResult::Ok`]. Only *transport-level* failures (the shell could not
688+/// reach the server at all) produce [`HttpResult::Err`].
690+/// To act on an error status, inspect [`HttpResponse::status`]:
693+/// # use crux_http::protocol::{HttpResult, HttpResponse};
694+/// # use crux_http::HttpError;
695+/// # fn handle(result: HttpResult) {
697+/// HttpResult::Ok(response) if response.status == 200 => { /* success */ }
698+/// HttpResult::Ok(response) if response.status == 404 => { /* not found */ }
699+/// HttpResult::Ok(response) if response.status >= 500 => { /* server error */ }
700+/// HttpResult::Ok(_) => { /* other status */ }
701+/// HttpResult::Err(e) => { /* transport failure: bad URL, IO error, or timeout */ }
705+sealed interface HttpResult {
706+ fun serialize(serializer: Serializer)
708+ fun bincodeSerialize(): ByteArray {
709+ val serializer = BincodeSerializer()
710+ serialize(serializer)
711+ return serializer.get_bytes()
714+ /// The shell completed the HTTP exchange. The response may carry any status code,
715+ /// including 4xx and 5xx — inspect [`HttpResponse::status`] to distinguish them.
717+ val value: soy.iko.opencode.core.HttpResponse,
719+ override fun serialize(serializer: Serializer) {
720+ serializer.increase_container_depth()
721+ serializer.serialize_variant_index(0)
722+ value.serialize(serializer)
723+ serializer.decrease_container_depth()
727+ fun deserialize(deserializer: Deserializer): Ok {
728+ deserializer.increase_container_depth()
729+ val value = soy.iko.opencode.core.HttpResponse.deserialize(deserializer)
730+ deserializer.decrease_container_depth()
736+ /// The shell could not complete the HTTP exchange due to a transport-level failure.
737+ /// See [`HttpError`] for the possible causes.
739+ val value: soy.iko.opencode.core.HttpError,
741+ override fun serialize(serializer: Serializer) {
742+ serializer.increase_container_depth()
743+ serializer.serialize_variant_index(1)
744+ value.serialize(serializer)
745+ serializer.decrease_container_depth()
749+ fun deserialize(deserializer: Deserializer): Err {
750+ deserializer.increase_container_depth()
751+ val value = soy.iko.opencode.core.HttpError.deserialize(deserializer)
752+ deserializer.decrease_container_depth()
759+ @Throws(DeserializationError::class)
760+ fun deserialize(deserializer: Deserializer): HttpResult {
761+ val index = deserializer.deserialize_variant_index()
762+ return when (index) {
763+ 0 -> Ok.deserialize(deserializer)
764+ 1 -> Err.deserialize(deserializer)
765+ else -> throw DeserializationError("Unknown variant index for HttpResult: $index")
769+ @Throws(DeserializationError::class)
770+ fun bincodeDeserialize(input: ByteArray?): HttpResult {
771+ if (input == null) {
772+ throw DeserializationError("Cannot deserialize null array")
774+ val deserializer = BincodeDeserializer(input)
775+ val value = deserialize(deserializer)
776+ if (deserializer.get_buffer_offset() < input.size) {
777+ throw DeserializationError("Some input bytes were not read")
784+data class MessageView(
790+ fun serialize(serializer: Serializer) {
791+ serializer.increase_container_depth()
792+ serializer.serialize_str(id)
793+ serializer.serialize_str(role)
794+ serializer.serialize_str(text)
795+ serializer.serialize_u64(time)
796+ serializer.decrease_container_depth()
799+ fun bincodeSerialize(): ByteArray {
800+ val serializer = BincodeSerializer()
801+ serialize(serializer)
802+ return serializer.get_bytes()
806+ fun deserialize(deserializer: Deserializer): MessageView {
807+ deserializer.increase_container_depth()
808+ val id = deserializer.deserialize_str()
809+ val role = deserializer.deserialize_str()
810+ val text = deserializer.deserialize_str()
811+ val time = deserializer.deserialize_u64()
812+ deserializer.decrease_container_depth()
813+ return MessageView(id, role, text, time)
816+ @Throws(DeserializationError::class)
817+ fun bincodeDeserialize(input: ByteArray?): MessageView {
818+ if (input == null) {
819+ throw DeserializationError("Cannot deserialize null array")
821+ val deserializer = BincodeDeserializer(input)
822+ val value = deserialize(deserializer)
823+ if (deserializer.get_buffer_offset() < input.size) {
824+ throw DeserializationError("Some input bytes were not read")
831+/// The single operation `Render` implements.
832+data object RenderOperation {
833+ fun serialize(serializer: Serializer) {}
835+ fun bincodeSerialize(): ByteArray {
836+ val serializer = BincodeSerializer()
837+ serialize(serializer)
838+ return serializer.get_bytes()
841+ fun deserialize(deserializer: Deserializer): RenderOperation {
842+ return RenderOperation
845+ @Throws(DeserializationError::class)
846+ fun bincodeDeserialize(input: ByteArray?): RenderOperation {
847+ if (input == null) {
848+ throw DeserializationError("Cannot deserialize null array")
850+ val deserializer = BincodeDeserializer(input)
851+ val value = deserialize(deserializer)
852+ if (deserializer.get_buffer_offset() < input.size) {
853+ throw DeserializationError("Some input bytes were not read")
859+/// Request for a side-effect passed from the Core to the Shell.
861+/// The `EffectId` links the `Request` with the corresponding call to [`Core::resolve`] to pass the data back
862+/// to the [`App::update`] function (wrapped in the event provided to the capability originating the effect).
865+ val effect: soy.iko.opencode.core.Effect,
867+ fun serialize(serializer: Serializer) {
868+ serializer.increase_container_depth()
869+ serializer.serialize_u32(id)
870+ effect.serialize(serializer)
871+ serializer.decrease_container_depth()
874+ fun bincodeSerialize(): ByteArray {
875+ val serializer = BincodeSerializer()
876+ serialize(serializer)
877+ return serializer.get_bytes()
881+ fun deserialize(deserializer: Deserializer): Request {
882+ deserializer.increase_container_depth()
883+ val id = deserializer.deserialize_u32()
884+ val effect = soy.iko.opencode.core.Effect.deserialize(deserializer)
885+ deserializer.decrease_container_depth()
886+ return Request(id, effect)
889+ @Throws(DeserializationError::class)
890+ fun bincodeDeserialize(input: ByteArray?): Request {
891+ if (input == null) {
892+ throw DeserializationError("Cannot deserialize null array")
894+ val deserializer = BincodeDeserializer(input)
895+ val value = deserialize(deserializer)
896+ if (deserializer.get_buffer_offset() < input.size) {
897+ throw DeserializationError("Some input bytes were not read")
904+/// A batch of effect requests from the Core to the Shell, as serialised by
905+/// [`Bridge::update`] and [`Bridge::resolve`].
907+/// The wire format is identical to `Vec<Request<Eff>>` (the newtype is
908+/// `serde(transparent)`), so existing shell code that already deserialises
909+/// a `Vec<Request>` remains binary-compatible.
911+/// Registering this type with the type-generation system causes the code
912+/// generators to emit a `Requests` type (with a `value` field containing the
913+/// list) together with a top-level `bincodeDeserialize` / `BincodeDeserialize`
914+/// helper, replacing the hand-written extension files that were previously
915+/// appended by `add_extensions()`.
917+ val value: List<soy.iko.opencode.core.Request>,
919+ fun serialize(serializer: Serializer) {
920+ serializer.increase_container_depth()
921+ value.serialize(serializer) {
922+ it.serialize(serializer)
924+ serializer.decrease_container_depth()
927+ fun bincodeSerialize(): ByteArray {
928+ val serializer = BincodeSerializer()
929+ serialize(serializer)
930+ return serializer.get_bytes()
934+ fun deserialize(deserializer: Deserializer): Requests {
935+ deserializer.increase_container_depth()
937+ deserializer.deserializeListOf {
938+ soy.iko.opencode.core.Request.deserialize(deserializer)
940+ deserializer.decrease_container_depth()
941+ return Requests(value)
944+ @Throws(DeserializationError::class)
945+ fun bincodeDeserialize(input: ByteArray?): Requests {
946+ if (input == null) {
947+ throw DeserializationError("Cannot deserialize null array")
949+ val deserializer = BincodeDeserializer(input)
950+ val value = deserialize(deserializer)
951+ if (deserializer.get_buffer_offset() < input.size) {
952+ throw DeserializationError("Some input bytes were not read")
964+ fun serialize(serializer: Serializer) {
965+ serializer.increase_container_depth()
966+ serializer.serialize_variant_index(ordinal)
967+ serializer.decrease_container_depth()
970+ fun bincodeSerialize(): ByteArray {
971+ val serializer = BincodeSerializer()
972+ serialize(serializer)
973+ return serializer.get_bytes()
977+ @Throws(DeserializationError::class)
978+ fun deserialize(deserializer: Deserializer): Screen {
979+ deserializer.increase_container_depth()
980+ val index = deserializer.deserialize_variant_index()
981+ deserializer.decrease_container_depth()
982+ return when (index) {
986+ else -> throw DeserializationError("Unknown variant index for Screen: $index")
990+ @Throws(DeserializationError::class)
991+ fun bincodeDeserialize(input: ByteArray?): Screen {
992+ if (input == null) {
993+ throw DeserializationError("Cannot deserialize null array")
995+ val deserializer = BincodeDeserializer(input)
996+ val value = deserialize(deserializer)
997+ if (deserializer.get_buffer_offset() < input.size) {
998+ throw DeserializationError("Some input bytes were not read")
1005+data class SessionView(
1009+ fun serialize(serializer: Serializer) {
1010+ serializer.increase_container_depth()
1011+ serializer.serialize_str(id)
1012+ serializer.serialize_str(title)
1013+ serializer.decrease_container_depth()
1016+ fun bincodeSerialize(): ByteArray {
1017+ val serializer = BincodeSerializer()
1018+ serialize(serializer)
1019+ return serializer.get_bytes()
1023+ fun deserialize(deserializer: Deserializer): SessionView {
1024+ deserializer.increase_container_depth()
1025+ val id = deserializer.deserialize_str()
1026+ val title = deserializer.deserialize_str()
1027+ deserializer.decrease_container_depth()
1028+ return SessionView(id, title)
1031+ @Throws(DeserializationError::class)
1032+ fun bincodeDeserialize(input: ByteArray?): SessionView {
1033+ if (input == null) {
1034+ throw DeserializationError("Cannot deserialize null array")
1036+ val deserializer = BincodeDeserializer(input)
1037+ val value = deserialize(deserializer)
1038+ if (deserializer.get_buffer_offset() < input.size) {
1039+ throw DeserializationError("Some input bytes were not read")
1046+data class ViewModel(
1047+ val screen: soy.iko.opencode.core.Screen,
1048+ val serverUrl: String,
1049+ val username: String,
1050+ val password: String,
1051+ val authRequired: Boolean,
1052+ val connected: Boolean,
1053+ val loading: Boolean,
1054+ val error: String? = null,
1055+ val sessions: List<soy.iko.opencode.core.SessionView>,
1056+ val currentSessionId: String? = null,
1057+ val messages: List<soy.iko.opencode.core.MessageView>,
1058+ val draftMessage: String,
1059+ val crashLogCount: UInt,
1060+ val latestCrashLog: String? = null,
1062+ fun serialize(serializer: Serializer) {
1063+ serializer.increase_container_depth()
1064+ screen.serialize(serializer)
1065+ serializer.serialize_str(serverUrl)
1066+ serializer.serialize_str(username)
1067+ serializer.serialize_str(password)
1068+ serializer.serialize_bool(authRequired)
1069+ serializer.serialize_bool(connected)
1070+ serializer.serialize_bool(loading)
1071+ error.serializeOptionOf(serializer) {
1072+ serializer.serialize_str(it)
1074+ sessions.serialize(serializer) {
1075+ it.serialize(serializer)
1077+ currentSessionId.serializeOptionOf(serializer) {
1078+ serializer.serialize_str(it)
1080+ messages.serialize(serializer) {
1081+ it.serialize(serializer)
1083+ serializer.serialize_str(draftMessage)
1084+ serializer.serialize_u32(crashLogCount)
1085+ latestCrashLog.serializeOptionOf(serializer) {
1086+ serializer.serialize_str(it)
1088+ serializer.decrease_container_depth()
1091+ fun bincodeSerialize(): ByteArray {
1092+ val serializer = BincodeSerializer()
1093+ serialize(serializer)
1094+ return serializer.get_bytes()
1098+ fun deserialize(deserializer: Deserializer): ViewModel {
1099+ deserializer.increase_container_depth()
1100+ val screen = soy.iko.opencode.core.Screen.deserialize(deserializer)
1101+ val serverUrl = deserializer.deserialize_str()
1102+ val username = deserializer.deserialize_str()
1103+ val password = deserializer.deserialize_str()
1104+ val authRequired = deserializer.deserialize_bool()
1105+ val connected = deserializer.deserialize_bool()
1106+ val loading = deserializer.deserialize_bool()
1108+ deserializer.deserializeOptionOf {
1109+ deserializer.deserialize_str()
1112+ deserializer.deserializeListOf {
1113+ soy.iko.opencode.core.SessionView.deserialize(deserializer)
1115+ val currentSessionId =
1116+ deserializer.deserializeOptionOf {
1117+ deserializer.deserialize_str()
1120+ deserializer.deserializeListOf {
1121+ soy.iko.opencode.core.MessageView.deserialize(deserializer)
1123+ val draftMessage = deserializer.deserialize_str()
1124+ val crashLogCount = deserializer.deserialize_u32()
1125+ val latestCrashLog =
1126+ deserializer.deserializeOptionOf {
1127+ deserializer.deserialize_str()
1129+ deserializer.decrease_container_depth()
1130+ return ViewModel(screen, serverUrl, username, password, authRequired, connected, loading, error, sessions, currentSessionId, messages, draftMessage, crashLogCount, latestCrashLog)
1133+ @Throws(DeserializationError::class)
1134+ fun bincodeDeserialize(input: ByteArray?): ViewModel {
1135+ if (input == null) {
1136+ throw DeserializationError("Cannot deserialize null array")
1138+ val deserializer = BincodeDeserializer(input)
1139+ val value = deserialize(deserializer)
1140+ if (deserializer.get_buffer_offset() < input.size) {
1141+ throw DeserializationError("Some input bytes were not read")