diff --git a/.ffi-version b/.ffi-version index a05707f..b316b8f 100644 --- a/.ffi-version +++ b/.ffi-version @@ -1,4 +1,4 @@ # Bump this when upgrading the FFI, then run `node scripts/install.mjs`. # (`ffi/` for releases, `prerelease/` for prereleases). -# See releases from https://github.com/webview-bundle/webview-bundles. -prerelease/76b4cbf +# See releases from https://github.com/webview-bundle/webview-bundle. +prerelease/f62e1f4 diff --git a/README.md b/README.md index f0f63e4..194bc73 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,9 @@ mise install ## Installing / updating the FFI module `scripts/install.mjs` fetches a release from the upstream repository and wires -it into the `lib` module. From the `android.zip` asset it installs the Android -variant (`lib-android`): +it into the `lib` module. -- the Kotlin bindings into `lib/src/main/kotlin/` +- `WvbFFI.kt` and `WvbRustlsPlatformVerififer.kt` into `lib/src/main/kotlin/dev/wvb/` - the JNI libraries (a `libwvb_ffi.so` per ABI) into `lib/src/main/jniLibs/` The Kotlin bindings are overwritten in place; `jniLibs` is replaced wholesale, diff --git a/e2e/README.md b/e2e/README.md index 422e2da..e77e9b5 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -5,12 +5,13 @@ Appium-driven end-to-end tests for the `testapp` module, mirroring the iOS e2e. ## How it works The `testapp` (`MainActivity`) is a minimal WebView host: it serves the builtin -`testbed` bundle (0.2.0) over `https://testbed.wvb/` and loads it on launch, and -wires its updater to the live playground remote -(`https://playground-remote.wvb.dev`, which hosts 0.3.0). It carries **no** test -logic of its own. The scenarios live in the shared -`@wvb-playground/webview-testbed` package and are expressed against the -platform-agnostic `WebviewDriver` from `@wvb-playground/testdriver`. +`testbed` bundle (0.4.0) over `https://testbed.wvb/` and loads it on launch, and +wires its updater to the playground remote for manual use. E2E supplies a local +remote endpoint through the test app's `wvbRemoteUrl` launch argument. The shared +suite fills the testbed's inputs, clicks its buttons and checks rendered results. +It downloads 0.4.1 and 0.4.2, verifies the page version after each installation, +and checks that rollback loads the previous UI. Downloads use the Android +emulator's `10.0.2.2` host alias. The Appium session is switched into the testapp's **WEBVIEW** context, then the suite runs through `createAppiumDriver(driver, { baseURL: "https://testbed.wvb" })`, @@ -24,17 +25,16 @@ which drives the live DOM (CSS selectors, in-app navigation via `goto`). (or reuses) an emulator, starts an Appium server (with `chromedriver_autodownload` enabled), opens a session that installs and launches the testapp, and switches into its WEBVIEW context. -- **testbed.spec.ts** registers the `@wvb-playground/webview-testbed/testing` - suite (`defineTestbedSuite`) — one case per `@wvb/bridge` method — plus a strict - end-to-end check that downloads the real remote bundle and updates the source - from the builtin 0.2.0 to the remote 0.3.0. +- **testbed.spec.ts** runs the shared UI suite for all 26 bridge methods, plus + update-document, manifest, download/install/rollback and invalid-input scenarios. ## Prerequisites - The Android SDK, with `platform-tools` (adb) and `emulator` available. Set `ANDROID_HOME` (or `ANDROID_SDK_ROOT`) if it is not at the platform default. - At least one AVD. The first one is used unless `ANDROID_AVD` is set; an - already-booted device/emulator is reused. + already-booted emulator is reused. Physical devices are skipped because the + fixture remote uses the emulator's `10.0.2.2` host alias. - Node + a package manager (the repo pins toolchain via `mise`). - Appium is installed as a dev dependency; the `uiautomator2` driver is installed into `~/.appium` on first run. @@ -52,3 +52,4 @@ Environment knobs: - `ANDROID_AVD` — AVD to boot when no device is already running. - `WVB_E2E_HEADLESS=1` — boot the emulator with `-no-window` (default on `CI`). - `WVB_E2E_KEEP=1` — leave a self-booted emulator running after the test. +- `APPIUM_PORT` — server port (default `4723`); choose different ports when running iOS and Android suites together. diff --git a/e2e/appium.ts b/e2e/appium.ts index 52a5e70..0a3b337 100644 --- a/e2e/appium.ts +++ b/e2e/appium.ts @@ -3,7 +3,7 @@ import path from "node:path"; import { setTimeout as delay } from "node:timers/promises"; import { execa, type ResultPromise } from "execa"; -export const APPIUM_PORT = 4723; +export const APPIUM_PORT = Number(process.env.APPIUM_PORT ?? 4723); if (!process.env.APPIUM_HOME) { process.env.APPIUM_HOME = path.join(os.homedir(), ".appium"); diff --git a/e2e/context.ts b/e2e/context.ts index 7c9f7e5..4286631 100644 --- a/e2e/context.ts +++ b/e2e/context.ts @@ -1,3 +1,4 @@ +import { startFixtureRemote, type FixtureRemote } from "./remote.js"; import fs from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; @@ -22,6 +23,7 @@ export type Driver = Awaited>; export interface TestContext { server: AppiumServer; + fixtureRemote: FixtureRemote; device: AndroidDevice; driver: Driver; } @@ -69,6 +71,7 @@ export async function createTestContext(): Promise { const device = await ensureAndroidDevice(); const server = await startAppiumServer(APPIUM_PORT); + const fixtureRemote = await startFixtureRemote("10.0.2.2"); const sessionTimeout = process.env.CI ? 720_000 : 360_000; @@ -90,6 +93,7 @@ export async function createTestContext(): Promise { "appium:appPackage": APP_PACKAGE, "appium:appActivity": APP_ACTIVITY, "appium:appWaitActivity": "*", + "appium:optionalIntentArguments": `--es wvbRemoteUrl ${fixtureRemote.endpoint}`, // The testapp's versionCode is constant, so without a full reset Appium // skips reinstalling a rebuilt APK and keeps stale bundles/assets. "appium:fullReset": true, @@ -108,7 +112,7 @@ export async function createTestContext(): Promise { await switchToWebview(driver); - return { server, device, driver }; + return { server, device, driver, fixtureRemote }; } /** ms to wait for the testapp's WebView to expose a debuggable WEBVIEW context. */ @@ -145,6 +149,7 @@ export async function disposeTestContext( } await context.driver.deleteSession().catch(() => {}); await context.server.stop(); + await context.fixtureRemote.close(); if (context.device.bootedByUs && !process.env.WVB_E2E_KEEP) { await context.device.shutdown(); } diff --git a/e2e/device.ts b/e2e/device.ts index 1e6415c..05100cf 100644 --- a/e2e/device.ts +++ b/e2e/device.ts @@ -154,7 +154,7 @@ async function bootEmulator(avd: string): Promise { } /** - * Reuses an already-booted device/emulator, or boots an AVD and waits for it to + * Reuses an already-booted emulator, or boots an AVD and waits for it to * finish booting. */ export async function ensureAndroidDevice( @@ -163,6 +163,8 @@ export async function ensureAndroidDevice( await adb(["start-server"]); for (const serial of await listSerials()) { + // The fixture remote uses 10.0.2.2, which is only reachable from an emulator. + if (!serial.startsWith("emulator-")) continue; if (await isBooted(serial)) { console.log(`[device] reusing running device: ${serial}`); return { diff --git a/e2e/fixtures/0.4.1.wvb b/e2e/fixtures/0.4.1.wvb new file mode 100644 index 0000000..2c0dcd9 Binary files /dev/null and b/e2e/fixtures/0.4.1.wvb differ diff --git a/e2e/fixtures/0.4.2.wvb b/e2e/fixtures/0.4.2.wvb new file mode 100644 index 0000000..aeca99e Binary files /dev/null and b/e2e/fixtures/0.4.2.wvb differ diff --git a/e2e/fixtures/webview-testbed-0.4.0.tgz b/e2e/fixtures/webview-testbed-0.4.0.tgz new file mode 100644 index 0000000..b95f731 Binary files /dev/null and b/e2e/fixtures/webview-testbed-0.4.0.tgz differ diff --git a/e2e/package.json b/e2e/package.json index fa1edb8..12b7b11 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@wvb-playground/testdriver": "0.1.0", - "@wvb-playground/webview-testbed": "0.3.0" + "@wvb-playground/webview-testbed": "file:./fixtures/webview-testbed-0.4.0.tgz" }, "devDependencies": { "@types/node": "^25", diff --git a/e2e/remote.ts b/e2e/remote.ts new file mode 100644 index 0000000..60ddc7d --- /dev/null +++ b/e2e/remote.ts @@ -0,0 +1,77 @@ +import { createHash } from "node:crypto"; +import { readFile } from "node:fs/promises"; +import { createServer } from "node:http"; +import type { AddressInfo } from "node:net"; + +export async function startFixtureRemote(host: string) { + const bundles = new Map( + await Promise.all( + ["0.4.1", "0.4.2"].map( + async (version) => + [ + version, + await readFile( + new URL(`./fixtures/${version}.wvb`, import.meta.url), + ), + ] as const, + ), + ), + ); + let version = "0.4.1"; + const server = createServer((request, response) => { + const path = new URL(request.url ?? "/", "http://localhost").pathname; + if (path === "/update") { + const etag = `"testbed-${version}"`; + if (request.headers["if-none-match"] === etag) { + response.writeHead(304).end(); + return; + } + const bytes = bundles.get(version)!; + response.writeHead(200, { "content-type": "application/json", etag }); + response.end( + JSON.stringify({ + id: `testbed-${version}`, + createdAt: "2026-10-09T00:00:00Z", + runtimeVersion: 1, + bundles: [ + { + name: "testbed", + version, + integrity: `sha256:${createHash("sha256").update(bytes).digest("base64")}`, + }, + ], + metadata: { channel: "stable" }, + }), + ); + return; + } + const match = /^\/bundles\/testbed\/([^/]+)$/.exec(path); + const bytes = match ? bundles.get(match[1]!) : undefined; + if (!bytes) { + response.writeHead(404).end(); + return; + } + response.writeHead(200, { + "content-type": "application/octet-stream", + "content-length": bytes.length, + }); + response.end(bytes); + }); + await new Promise((resolve, reject) => { + server.once("error", reject); + server.listen(0, "0.0.0.0", resolve); + }); + return { + endpoint: `http://${host}:${(server.address() as AddressInfo).port}`, + setVersion(next: string) { + if (!bundles.has(next)) + throw new Error(`Unknown fixture version: ${next}`); + version = next; + }, + close: () => + new Promise((resolve, reject) => + server.close((error) => (error ? reject(error) : resolve())), + ), + }; +} +export type FixtureRemote = Awaited>; diff --git a/e2e/testbed.spec.ts b/e2e/testbed.spec.ts index 0afbd0a..314d6c5 100644 --- a/e2e/testbed.spec.ts +++ b/e2e/testbed.spec.ts @@ -1,134 +1,24 @@ import { createAppiumDriver } from "@wvb-playground/testdriver/appium"; import { - methodSel, - sel, - testCases, + defineTestbedSuite, + defineTestbedUpdateSuite, type WebviewDriver, } from "@wvb-playground/webview-testbed/testing"; -import { beforeAll, describe, expect, test } from "vitest"; -import { type Driver, getTestContext } from "./context.js"; +import { beforeAll, describe } from "vitest"; +import { getTestContext } from "./context.js"; -// Drives the `@wvb-playground/webview-testbed` bundle inside the Android WebView. The -// testapp ships the builtin `testbed` bundle and points its updater at the live -// playground remote (https://playground-remote.wvb.dev). -describe("testbed (android)", () => { - const BASE_URL = "https://testbed.wvb"; - const BUNDLE = "testbed"; - const BUILTIN_VERSION = "0.2.0"; - const REMOTE_VERSION = "0.3.0"; - - // Loading the app shell (a full navigation) and the network download need more - // headroom than the driver's default. - const NAV_TIMEOUT = 30_000; - const RESULT_TIMEOUT = 90_000; - - let browser: Driver; +describe("testbed UI (android)", () => { let driver: WebviewDriver; - beforeAll(() => { - browser = getTestContext().driver; - driver = createAppiumDriver(browser, { - baseURL: BASE_URL, - defaultTimeoutMs: NAV_TIMEOUT, + driver = createAppiumDriver(getTestContext().driver, { + baseURL: "https://testbed.wvb", + defaultTimeoutMs: 30_000, }); }); - async function open(): Promise { - await driver.goto("/"); - await driver.waitForVisible(sel.appShell, { timeoutMs: NAV_TIMEOUT }); - } - - /** - * Runs one testbed method card on a freshly-loaded page and returns its terminal - * outcome. Reloading first guarantees the card starts idle (its result element is - * only rendered once a call settles), so waiting for the result can never observe a - * stale value left by an earlier run of the same method. - */ - async function runMethod( - id: string, - params: Record = {}, - ): Promise<{ status: string | null; text: string }> { - await open(); - for (const [name, value] of Object.entries(params)) { - await driver.fill(methodSel.param(id, name), value); - } - await driver.click(methodSel.run(id)); - await driver.waitForVisible(methodSel.result(id), { timeoutMs: RESULT_TIMEOUT }); - const outcome = { - status: await driver.getAttribute(methodSel.result(id), "data-status"), - text: await driver.text(methodSel.result(id)), - }; - console.log(`[testbed] ${id} -> ${outcome.status}: ${outcome.text}`); - return outcome; - } - - function parseJson(text: string): Record { - try { - return JSON.parse(text) as Record; - } catch { - throw new Error(`expected a JSON result, got: ${text}`); - } - } - - // The only test that *asserts* the real remote download succeeds. Skipped on CI: - // this fill + reload + download sequence hangs on the GitHub Actions Android emulator - // (the network is reachable — the generic suite below downloads over it — but this - // specific flow stalls there). It passes locally, and the generic suite still - // exercises the download (as ok|error) on CI. - test.skipIf(!!process.env.CI)( - "downloads + installs the real remote update (builtin 0.2.0 -> remote 0.3.0)", - async () => { - await open(); - expect(await driver.text(sel.platformType)).toBe("android"); - - const before = parseJson( - (await runMethod("source.loadVersion", { bundleName: BUNDLE })).text, - ); - expect(before).toEqual({ type: "builtin", version: BUILTIN_VERSION }); - - const update = await runMethod("updater.getUpdate", { bundleName: BUNDLE }); - expect(update.status).toBe("ok"); - const info = parseJson(update.text); - expect(info.name).toBe(BUNDLE); - expect(info.version).toBe(REMOTE_VERSION); - expect(info.isAvailable).toBe(true); - expect(info.localVersion).toBe(BUILTIN_VERSION); - - const download = await runMethod("updater.download", { bundleName: BUNDLE }); - expect(download.status).toBe("ok"); - expect(parseJson(download.text).version).toBe(REMOTE_VERSION); - - const install = await runMethod("updater.install", { - bundleName: BUNDLE, - version: REMOTE_VERSION, - }); - expect(install.status).toBe("ok"); - - const after = parseJson( - (await runMethod("source.loadVersion", { bundleName: BUNDLE })).text, - ); - expect(after).toEqual({ type: "remote", version: REMOTE_VERSION }); - - // Drop the cached descriptor so the next request loads the freshly-installed - // version, and cache-bust so the WebView can't serve stale HTML. - await runMethod("source.unloadDescriptor", { bundleName: BUNDLE }); - await driver.goto(`/?updated=${Date.now()}`); - await driver.waitForVisible(sel.appShell, { timeoutMs: NAV_TIMEOUT }); - expect(await driver.text(".app__version")).toContain(REMOTE_VERSION); - }, - 240_000, + defineTestbedUpdateSuite( + () => driver, + () => getTestContext().fixtureRemote, ); - - // The platform-agnostic suite the testbed package ships (each `@wvb/bridge` method - // asserted to render an ok|error outcome). The "raw invoke" case is the only one that - // fills a text input, which hangs on the CI Android emulator; skip it there (its - // coverage overlaps source.listBundles). Runs after the strict update test so it - // can't perturb that test's clean starting state. - for (const testCase of testCases) { - const register = - process.env.CI && testCase.name.startsWith("raw invoke") ? test.skip : test; - register(testCase.name, async () => { - await testCase.run(driver); - }); - } + defineTestbedSuite(() => driver); }); diff --git a/e2e/yarn.lock b/e2e/yarn.lock index a063c42..8e60395 100644 --- a/e2e/yarn.lock +++ b/e2e/yarn.lock @@ -698,13 +698,6 @@ __metadata: languageName: node linkType: hard -"@tauri-apps/api@npm:^2": - version: 2.11.1 - resolution: "@tauri-apps/api@npm:2.11.1" - checksum: 10c0/78a08a64ee7eab9d34bd4ba1bdc3a2440c7e9cc5737b3f1d77bd80fa38b0cb5e9601efe04da40c947c5da2ca38dc702bec21b4ae96b18ee5f3e82980d1f0b325 - languageName: node - linkType: hard - "@tootallnate/quickjs-emscripten@npm:^0.23.0": version: 0.23.0 resolution: "@tootallnate/quickjs-emscripten@npm:0.23.0" @@ -991,24 +984,14 @@ __metadata: languageName: node linkType: hard -"@wvb-playground/webview-testbed@npm:0.3.0": - version: 0.3.0 - resolution: "@wvb-playground/webview-testbed@npm:0.3.0" +"@wvb-playground/webview-testbed@file:./fixtures/webview-testbed-0.4.0.tgz::locator=webview-bundle-android-e2e%40workspace%3A.": + version: 0.4.0 + resolution: "@wvb-playground/webview-testbed@file:./fixtures/webview-testbed-0.4.0.tgz#./fixtures/webview-testbed-0.4.0.tgz::hash=7cded0&locator=webview-bundle-android-e2e%40workspace%3A." dependencies: "@wvb-playground/testdriver": "npm:^0.1.0" - "@wvb/bridge": "npm:0.1.0-next.fe10f84" peerDependencies: - vitest: ^2.0.0 || ^3.0.0 || ^4.0.0 - checksum: 10c0/b4243848ce25c46480269003d8b8edc25a052643d82db9bb51ae4bfe4407b73fa58503ca0aac06f2d17b7e63fb68bcddb5aa96f891f117f81129d2f58bbffd90 - languageName: node - linkType: hard - -"@wvb/bridge@npm:0.1.0-next.fe10f84": - version: 0.1.0-next.fe10f84 - resolution: "@wvb/bridge@npm:0.1.0-next.fe10f84" - dependencies: - "@tauri-apps/api": "npm:^2" - checksum: 10c0/dda6994a2826e07e93463576e5e50c7a24a2c4943af47f550862c26f4a95169e8b5fba1e7636aa3e9b245243e32f23c13e18c849d57f028833df749af6368aea + vitest: ^4.0.0 + checksum: 10c0/8ad4d176b228df9f8c1da9fff2a5ede0b64ebc553bf25ae4eea2b7cadce529fc90f289cc82a5ccf33c9e033842a4bee80f9dba47ee412c83349ed8089c1aa10d languageName: node linkType: hard @@ -5554,7 +5537,7 @@ __metadata: dependencies: "@types/node": "npm:^25" "@wvb-playground/testdriver": "npm:0.1.0" - "@wvb-playground/webview-testbed": "npm:0.3.0" + "@wvb-playground/webview-testbed": "file:./fixtures/webview-testbed-0.4.0.tgz" appium: "npm:^3.5.0" execa: "npm:^9.5.2" tinyglobby: "npm:^0.2.10" diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 9c802ce..5980998 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -28,6 +28,7 @@ android { defaultConfig { minSdk = 24 + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" // Keep the @JavascriptInterface bridge methods in minified consumer apps. consumerProguardFiles("consumer-rules.pro") } @@ -57,6 +58,12 @@ android { } dependencies { + // Match the rustls-platform-verifier-android crate used by the installed FFI. + implementation("org.rustls:rustls-platform-verifier:0.2.0") + androidTestImplementation("androidx.test:runner:1.6.2") + androidTestImplementation("junit:junit:4.13.2") + testImplementation("junit:junit:4.13.2") + testImplementation("org.json:json:20240303") implementation("net.java.dev.jna:jna:${libs.versions.jna.get()}@aar") implementation(libs.kotlinx.coroutines.core) implementation(libs.androidx.annotation) diff --git a/lib/consumer-rules.pro b/lib/consumer-rules.pro index 21f8119..b220e7b 100644 --- a/lib/consumer-rules.pro +++ b/lib/consumer-rules.pro @@ -1,4 +1,4 @@ -# WebViewBundle's native FFI bindings (lib/src/main/kotlin/dev/wvb/wvb_ffi.kt) +# WebViewBundle's native FFI bindings (lib/src/main/kotlin/dev/wvb/WvbFFI.kt) # are UniFFI-generated and call into the native library through JNA. JNA maps the # Rust structs/callbacks by reflection and reads the field names from # @Structure.FieldOrder annotations, so R8 in a minified consumer app must not @@ -14,3 +14,6 @@ -keep class com.sun.jna.* { *; } -keep class * extends com.sun.jna.* { *; } -keepclassmembers class * extends com.sun.jna.* { public *; } + +# Called from Rust through JNI. +-keep, includedescriptorclasses class org.rustls.platformverifier.** { *; } diff --git a/lib/lint.xml b/lib/lint.xml index c512edb..8145043 100644 --- a/lib/lint.xml +++ b/lib/lint.xml @@ -1,7 +1,7 @@ - + diff --git a/lib/src/androidTest/AndroidManifest.xml b/lib/src/androidTest/AndroidManifest.xml new file mode 100644 index 0000000..fbb2ef8 --- /dev/null +++ b/lib/src/androidTest/AndroidManifest.xml @@ -0,0 +1,3 @@ + + + diff --git a/lib/src/androidTest/kotlin/dev/wvb/AndroidTlsTest.kt b/lib/src/androidTest/kotlin/dev/wvb/AndroidTlsTest.kt new file mode 100644 index 0000000..97ba3b8 --- /dev/null +++ b/lib/src/androidTest/kotlin/dev/wvb/AndroidTlsTest.kt @@ -0,0 +1,48 @@ +package dev.wvb + +import androidx.test.platform.app.InstrumentationRegistry +import java.io.File +import kotlinx.coroutines.runBlocking +import org.junit.Assert.* +import org.junit.Test + +/** Network integration tests; require access to example.com and badssl.com. */ +class AndroidTlsTest { + @Test + fun httpsWorksAfterAutomaticInitializationAndRecreation() = runBlocking { + val context = InstrumentationRegistry.getInstrumentation().targetContext + val config = WebViewBundleConfig( + protocols = emptyList(), + updater = WebViewBundleUpdaterConfig(WebViewBundleRemoteConfig("https://example.com")), + ) + + repeat(2) { + WebViewBundle.getInstance(context, config).use { bundle -> + val destination = File(context.cacheDir, "tls-download.html") + try { + bundle.remote!!.download("https://example.com/", destination.absolutePath) + assertTrue(destination.readText().contains("Example Domain")) + } finally { + destination.delete() + } + + ProxyProtocolHandler(mapOf("tls-test" to "https://example.com")).use { proxy -> + val response = proxy.handle(HttpMethod.GET, "https://tls-test/") + assertEquals(200, response.status.toInt()) + assertTrue(response.body.toString(Charsets.UTF_8).contains("Example Domain")) + } + } + } + + WvbAndroid.initialize(context) + WvbAndroid.initialize(context) + ProxyProtocolHandler(mapOf("tls-test" to "https://self-signed.badssl.com")).use { proxy -> + try { + proxy.handle(HttpMethod.GET, "https://tls-test/") + fail("A self-signed certificate must be rejected") + } catch (_: WebviewBundleException.CoreHttpClient) { + // A verifier panic would surface as InternalException, not this typed error. + } + } + } +} diff --git a/lib/src/main/kotlin/dev/wvb/Bridge.kt b/lib/src/main/kotlin/dev/wvb/Bridge.kt index ff88c2b..787393f 100644 --- a/lib/src/main/kotlin/dev/wvb/Bridge.kt +++ b/lib/src/main/kotlin/dev/wvb/Bridge.kt @@ -143,7 +143,7 @@ class Bridge internal constructor() : AutoCloseable { fun encodeError(error: Throwable): String { val json = JSONObject().put("message", error.message ?: error.toString()) - (error as? BridgeFailure)?.code?.let { json.put("code", it) } + ((error as? BridgeFailure)?.code ?: (error as? WebviewBundleException)?.bridgeCode)?.let { json.put("code", it) } return json.toString() } diff --git a/lib/src/main/kotlin/dev/wvb/BridgeCodec.kt b/lib/src/main/kotlin/dev/wvb/BridgeCodec.kt index d2ed43b..b6f9404 100644 --- a/lib/src/main/kotlin/dev/wvb/BridgeCodec.kt +++ b/lib/src/main/kotlin/dev/wvb/BridgeCodec.kt @@ -1,71 +1,242 @@ package dev.wvb +import org.json.JSONArray import org.json.JSONObject -/** Decodes `invoke()` params into typed values. */ +/** The JSON contract is shared with @wvb/bridge. */ internal object BridgeCodec { - /** The params object, or an empty one when absent. */ - fun params(raw: Any?): JSONObject = raw as? JSONObject ?: JSONObject() -} - -/** A required string param; throws [BridgeError] if missing. */ -internal fun JSONObject.requireString(key: String): String { - if (!has(key) || isNull(key)) { - throw BridgeError(code = "invalid_params", message = "expected string param \"$key\"") + fun params(raw: Any?): JSONObject = when (raw) { + null, JSONObject.NULL -> JSONObject() + is JSONObject -> raw + else -> throw invalidParam("params") } - return getString(key) } -/** An optional string param; `null` when absent or JSON `null`. */ +private fun invalidParam(key: String) = + BridgeError(code = "invalid_params", message = "invalid param \"$key\"") + +internal fun JSONObject.requireString(key: String): String = + opt(key) as? String ?: throw invalidParam(key) + internal fun JSONObject.optionalString(key: String): String? = - if (!has(key) || isNull(key)) null else getString(key) + if (!has(key) || isNull(key)) null else requireString(key) + +internal fun JSONObject.requireObject(key: String): JSONObject = + opt(key) as? JSONObject ?: throw invalidParam(key) + +internal fun JSONObject.optionalObject(key: String): JSONObject? = + if (!has(key) || isNull(key)) null else requireObject(key) + +internal fun JSONObject.requireArray(key: String): JSONArray = + opt(key) as? JSONArray ?: throw invalidParam(key) + +internal fun JSONObject.optionalBoolean(key: String): Boolean? = + if (!has(key) || isNull(key)) null else opt(key) as? Boolean ?: throw invalidParam(key) + +internal fun JSONObject.optionalUnsigned(key: String, max: ULong = ULong.MAX_VALUE): ULong? { + if (!has(key) || isNull(key)) return null + val number = opt(key) as? Number ?: throw invalidParam(key) + val value = number.toString().toULongOrNull() ?: throw invalidParam(key) + if (value > max) throw invalidParam(key) + return value +} + +internal fun JSONObject.mapValues(decode: (JSONObject, String) -> T): Map = + keys().asSequence().associateWith { decode(this, it) } + +internal fun JSONObject.stringMap(): Map = mapValues { obj, key -> obj.requireString(key) } + +internal fun JSONArray.strings(): List = (0 until length()).map { + opt(it) as? String ?: throw invalidParam("[$it]") +} + +internal fun JSONArray.objects(decode: (JSONObject) -> T): List = (0 until length()).map { + decode(opt(it) as? JSONObject ?: throw invalidParam("[$it]")) +} + +internal fun JSONObject.versionData() = ManifestVersionData( + integrity = optionalString("integrity"), metadata = optionalObject("metadata")?.stringMap(), +) +internal fun JSONObject.stageData() = ManifestStageData( + version = requireString("version"), data = optionalObject("data")?.versionData(), +) +internal fun JSONObject.removeData() = ManifestRemoveData( + versions = requireArray("versions").strings(), force = optionalBoolean("force"), +) +internal fun JSONObject.bundleUpdate() = BundleUpdate( + name = requireString("name"), version = requireString("version"), + downloadUrl = optionalString("downloadUrl"), integrity = optionalString("integrity"), + metadata = optionalObject("metadata")?.stringMap(), +) + +internal fun SourceKind.bridgeValue(): String = when (this) { + SourceKind.BUILTIN -> "builtin" + SourceKind.REMOTE -> "remote" +} + +internal fun ManifestBundleItemStatus.bridgeValue(): String = when (this) { + ManifestBundleItemStatus.CURRENT -> "current" + ManifestBundleItemStatus.PREVIOUS -> "previous" + ManifestBundleItemStatus.STAGED -> "staged" + ManifestBundleItemStatus.ORPHAN -> "orphan" +} + +internal fun ManifestStageResultKind.bridgeValue(): String = when (this) { + ManifestStageResultKind.STAGED -> "staged" + ManifestStageResultKind.IN_USE -> "in_use" +} -// These mirror the JSON the web side consumes from the Electron bridge -// (`@wvb/node`): the source kind is keyed `type` on the wire, and nullable -// fields are omitted (putOpt) to match the TS optionals. +internal fun ManifestSetCurrentVersionResultKind.bridgeValue(): String = when (this) { + ManifestSetCurrentVersionResultKind.SETTLED -> "settled" + ManifestSetCurrentVersionResultKind.NOT_EXISTS -> "not_exists" + ManifestSetCurrentVersionResultKind.VERSION_NOT_EXISTS -> "version_not_exists" +} + +internal fun ManifestRemoveResultKind.bridgeValue(): String = when (this) { + ManifestRemoveResultKind.REMOVED -> "removed" + ManifestRemoveResultKind.NOT_EXISTS -> "not_exists" + ManifestRemoveResultKind.VERSION_NOT_EXISTS -> "version_not_exists" + ManifestRemoveResultKind.IN_USE -> "in_use" +} + +internal val WebviewBundleException.bridgeCode: String + get() = when (this) { + is WebviewBundleException.CoreIo -> "core.io" + is WebviewBundleException.CoreCompress -> "core.compress" + is WebviewBundleException.CoreDecompress -> "core.decompress" + is WebviewBundleException.CoreEncode -> "core.encode" + is WebviewBundleException.CoreDecode -> "core.decode" + is WebviewBundleException.CoreHttp -> "core.http" + is WebviewBundleException.CoreHttpInvalidUri -> "core.http_invalid_uri" + is WebviewBundleException.CoreCancelled -> "core.cancelled" + is WebviewBundleException.CoreTimeout -> "core.timeout" + is WebviewBundleException.CoreInvalidMagicNum -> "core.invalid_magic_num" + is WebviewBundleException.CoreInvalidVersion -> "core.invalid_version" + is WebviewBundleException.CoreInvalidHeaderChecksum -> "core.invalid_header_checksum" + is WebviewBundleException.CoreInvalidIndexChecksum -> "core.invalid_index_checksum" + is WebviewBundleException.CoreChecksumMismatch -> "core.checksum_mismatch" + is WebviewBundleException.CoreBundleNotFound -> "core.bundle_not_found" + is WebviewBundleException.CoreInvalidFilepath -> "core.invalid_filepath" + is WebviewBundleException.CoreSerdeJson -> "core.serde_json" + is WebviewBundleException.CoreCannotResolveProxyServer -> "core.cannot_resolve_proxy_server" + is WebviewBundleException.CoreHttpClient -> "core.http_client" + is WebviewBundleException.CoreRemoteHttp -> "core.remote_http" + is WebviewBundleException.CoreBadRemoteResponse -> "core.bad_remote_response" + is WebviewBundleException.CoreInvalidRemoteConfig -> "core.invalid_remote_config" + is WebviewBundleException.CoreInvalidUpdaterConfig -> "core.invalid_updater_config" + is WebviewBundleException.CoreInvalidIntegrity -> "core.invalid_integrity" + is WebviewBundleException.CoreIntegrityRequired -> "core.integrity_required" + is WebviewBundleException.CoreIntegrityVerifyFailed -> "core.integrity_verify_failed" + is WebviewBundleException.CoreInvalidSignature -> "core.invalid_signature" + is WebviewBundleException.CoreInvalidSignatureKey -> "core.invalid_signature_key" + is WebviewBundleException.CoreExpectSignatureNotFound -> "core.expect_signature_not_found" + is WebviewBundleException.CoreSignatureVerifyFailed -> "core.signature_verify_failed" + is WebviewBundleException.CoreGeneric -> "core.generic" + is WebviewBundleException.BindingInvalidHeaderName -> "invalid_header_name" + is WebviewBundleException.BindingInvalidHeaderValue -> "invalid_header_value" + is WebviewBundleException.BindingInvalidSignatureOptions -> "invalid_signature_options" + } + +internal fun UpdaterDownloadResultKind.toJson(): JSONObject = when (this) { + UpdaterDownloadResultKind.Downloaded -> JSONObject().put("type", "downloaded") + is UpdaterDownloadResultKind.Error -> JSONObject().put("type", "error") + .put("code", v1.bridgeCode).put("message", v1.message) +} + +internal fun UpdaterInstallResultKind.toJson(): JSONObject = when (this) { + UpdaterInstallResultKind.Installed -> JSONObject().put("type", "installed") + UpdaterInstallResultKind.StagedVersionNotMatched -> JSONObject().put("type", "staged_version_not_matched") + UpdaterInstallResultKind.StagedBundleNotExists -> JSONObject().put("type", "staged_bundle_not_exists") + UpdaterInstallResultKind.VerifyFailed -> JSONObject().put("type", "verify_failed") + is UpdaterInstallResultKind.Error -> JSONObject().put("type", "error") + .put("code", v1.bridgeCode).put("message", v1.message) +} -private fun BundleSourceKind.bridgeValue(): String = when (this) { - BundleSourceKind.BUILTIN -> "builtin" - BundleSourceKind.REMOTE -> "remote" +internal fun UpdaterRollbackResultKind.toJson(): JSONObject = when (this) { + UpdaterRollbackResultKind.RolledBack -> JSONObject().put("type", "rolled_back") + UpdaterRollbackResultKind.PreviousVersionNotMatched -> JSONObject().put("type", "previous_version_not_matched") + UpdaterRollbackResultKind.PreviousBundleNotExists -> JSONObject().put("type", "previous_bundle_not_exists") + UpdaterRollbackResultKind.VerifyFailed -> JSONObject().put("type", "verify_failed") + is UpdaterRollbackResultKind.Error -> JSONObject().put("type", "error") + .put("code", v1.bridgeCode).put("message", v1.message) } -internal fun BundleManifestMetadata.toJson(): JSONObject = - JSONObject() - .putOpt("etag", etag) - .putOpt("integrity", integrity) - .putOpt("signature", signature) - .putOpt("lastModified", lastModified) - -internal fun BundleSourceVersion.toJson(): JSONObject = - JSONObject().put("type", kind.bridgeValue()).put("version", version) - -internal fun ListBundleItem.toJson(): JSONObject = - JSONObject() - .put("type", kind.bridgeValue()) - .put("name", name) - .put("version", version) - .put("current", current) - .put("metadata", metadata.toJson()) - -internal fun ListRemoteBundleInfo.toJson(): JSONObject = - JSONObject().put("name", name).put("version", version) - -internal fun RemoteBundleInfo.toJson(): JSONObject = - JSONObject() - .put("name", name) - .put("version", version) - .putOpt("etag", etag) - .putOpt("integrity", integrity) - .putOpt("signature", signature) - .putOpt("lastModified", lastModified) - -internal fun BundleUpdateInfo.toJson(): JSONObject = - JSONObject() - .put("name", name) - .put("version", version) - .put("isAvailable", isAvailable) - .putOpt("localVersion", localVersion) - .putOpt("etag", etag) - .putOpt("integrity", integrity) - .putOpt("signature", signature) - .putOpt("lastModified", lastModified) +internal fun ManifestVersionData.toJson(): JSONObject = JSONObject() + .putOpt("integrity", integrity) + .putOpt("metadata", metadata?.let { JSONObject(it) }) + +internal fun BundleSourceVersion.toJson(): JSONObject = JSONObject() + .put("source", source.bridgeValue()) + .put("version", version) + +internal fun ManifestBundleItem.toJson(): JSONObject = JSONObject() + .put("name", name) + .put("version", version) + .put("status", status.bridgeValue()) + .put("data", data.toJson()) + +internal fun SourceListItem.toJson(): JSONObject = JSONObject() + .put("source", source.bridgeValue()) + .put("item", item.toJson()) + +internal fun ManifestStageResult.toJson(): JSONObject = JSONObject() + .put("name", name) + .put("version", version) + .put("kind", kind.bridgeValue()) + +internal fun ManifestSetCurrentVersionResult.toJson(): JSONObject = JSONObject() + .put("name", name) + .put("version", version) + .put("kind", kind.bridgeValue()) + +internal fun ManifestRemoveResult.toJson(): JSONObject = JSONObject() + .put("name", name) + .put("version", version) + .put("kind", kind.bridgeValue()) + +internal fun ManifestPruneResult.toJson(): JSONObject = JSONObject() + .put("name", name) + .put("prunedVersions", JSONArray(prunedVersions)) + +internal fun BundleUpdate.toJson(): JSONObject = JSONObject() + .put("name", name) + .put("version", version) + .putOpt("downloadUrl", downloadUrl) + .putOpt("integrity", integrity) + .putOpt("metadata", metadata?.let { JSONObject(it) }) + +internal fun Update.toJson(): JSONObject = JSONObject() + .put("id", id) + .put("createdAt", createdAt) + .put("runtimeVersion", runtimeVersion.toInt()) + .put("bundles", JSONArray(bundles.map { it.toJson() })) + .put("metadata", JSONObject(metadata)) + +internal fun UpdateSignature.toJson(): JSONObject = JSONObject() + .put("keyId", keyId) + .put("sig", sig) + .put("alg", alg) + +internal fun RemoteUpdateResponse.toJson(): JSONObject = JSONObject() + .put("update", update.toJson()) + .putOpt("etag", etag) + .putOpt("signature", signature?.toJson()) + +internal fun UpdaterDownloadResult.toJson(): JSONObject = JSONObject() + .put("name", name) + .put("version", version) + .putOpt("integrity", integrity) + .putOpt("metadata", metadata?.let { JSONObject(it) }) + .put("result", result.toJson()) + +internal fun UpdaterInstallResult.toJson(): JSONObject = JSONObject() + .put("name", name) + .putOpt("targetVersion", targetVersion) + .putOpt("installVersion", installVersion) + .put("result", result.toJson()) + +internal fun UpdaterRollbackResult.toJson(): JSONObject = JSONObject() + .put("name", name) + .putOpt("targetVersion", targetVersion) + .putOpt("rollbackVersion", rollbackVersion) + .put("result", result.toJson()) diff --git a/lib/src/main/kotlin/dev/wvb/Source.kt b/lib/src/main/kotlin/dev/wvb/Source.kt index 5a15fc8..981e181 100644 --- a/lib/src/main/kotlin/dev/wvb/Source.kt +++ b/lib/src/main/kotlin/dev/wvb/Source.kt @@ -7,7 +7,7 @@ import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicLong /** - * Options for building a [BundleSource] with sensible Android defaults. Every field + * Options for building a [Source] with sensible Android defaults. Every field * is optional and falls back to an app-private directory when omitted. * * @property builtinAssetsDir when non-null, the APK `assets/` @@ -20,11 +20,11 @@ public data class SourceOptions( val builtinManifestFilepath: String? = null, val remoteManifestFilepath: String? = null, val builtinAssetsDir: String? = "bundles", - val integrity: BundleSourceIntegrityOptions? = null, - val signature: BundleSourceSignatureOptions? = null, + val integrity: SourceIntegrityOptions? = null, val dataReadOptions: DataReadOptions? = null, val headerReadOptions: HeaderReadOptions? = null, val indexReadOptions: IndexReadOptions? = null, + val removeBundleChunkSize: UInt? = null, ) /** `/.wvb/builtin/bundles` — the read-only directory for bundles shipped with the app. */ @@ -36,16 +36,16 @@ public fun defaultRemoteDir(context: Context): String = File(context.filesDir, ".wvb/remote/bundles").absolutePath /** - * Builds a [BundleSource] from [config], filling in default directories, copying + * Builds a [Source] from [config], filling in default directories, copying * bundled assets into the builtin dir, and creating the writable remote dir. * * Performs blocking file I/O; prefer building off the main thread when shipping * large builtin bundles. */ -public fun makeBundleSource( +public fun makeSource( context: Context, config: SourceOptions, -): BundleSource { +): Source { val builtinDir = config.builtinDir ?: defaultBuiltinDir(context) val remoteDir = config.remoteDir ?: defaultRemoteDir(context) @@ -56,18 +56,18 @@ public fun makeBundleSource( installBuiltinBundlesFromAssets(context, assetDir, builtinDir) } - val bundleConfig = BundleSourceConfig( + val bundleConfig = SourceConfig( builtinDir = builtinDir, remoteDir = remoteDir, builtinManifestFilepath = config.builtinManifestFilepath, remoteManifestFilepath = config.remoteManifestFilepath, integrity = config.integrity, - signature = config.signature, dataReadOptions = config.dataReadOptions, headerReadOptions = config.headerReadOptions, indexReadOptions = config.indexReadOptions, + removeBundleChunkSize = config.removeBundleChunkSize, ) - return BundleSource(bundleConfig) + return Source(bundleConfig) } /** Per-destination locks serializing concurrent same-process extraction. */ @@ -78,7 +78,7 @@ private val tmpCounter = AtomicLong(0) /** * Copies bundles shipped in the APK `assets/[assetDir]` (default `bundles/`) into - * [builtinDir] so the native [BundleSource] can read them as real files, returning + * [builtinDir] so the native [Source] can read them as real files, returning * the destination. Copies recursively as an additive overlay — files removed from * the assets in a later app version are **not** deleted from [builtinDir]. No-op * when the asset directory does not exist. diff --git a/lib/src/main/kotlin/dev/wvb/WebViewBundle.kt b/lib/src/main/kotlin/dev/wvb/WebViewBundle.kt index a35ac81..624292a 100644 --- a/lib/src/main/kotlin/dev/wvb/WebViewBundle.kt +++ b/lib/src/main/kotlin/dev/wvb/WebViewBundle.kt @@ -11,7 +11,8 @@ import kotlinx.coroutines.runBlocking /** Remote endpoint configuration for [WebViewBundleUpdaterConfig]. */ data class WebViewBundleRemoteConfig( /** The base URL of the remote server, e.g. `"https://bundles.example.com"`. */ - val endpoint: String, + val baseUrl: String, + val options: RemoteOptions? = null, ) /** Updater configuration for [WebViewBundleConfig]. */ @@ -19,8 +20,10 @@ data class WebViewBundleUpdaterConfig( val remote: WebViewBundleRemoteConfig, /** Release channel (e.g. `"stable"`, `"beta"`). */ val channel: String? = null, - val integrityPolicy: IntegrityPolicy? = null, - val signatureVerifier: SignatureVerifierOptions? = null, + val integrity: UpdaterIntegrityOptions? = null, + val signature: UpdaterSignatureOptions? = null, + /** Persisted update document; defaults to `/update.json`. */ + val updateFilepath: String? = null, ) /** @@ -65,7 +68,7 @@ private class RegisteredProtocol( */ class WebViewBundle private constructor( /** The bundle source requests are served from. */ - val source: BundleSource, + val source: Source, /** The remote endpoint, when an [WebViewBundleUpdaterConfig] was provided. */ val remote: Remote?, /** The updater, when an [WebViewBundleUpdaterConfig] was provided. */ @@ -174,27 +177,27 @@ class WebViewBundle private constructor( getInstance(context, config) private fun create(context: Context, config: WebViewBundleConfig): WebViewBundle { - val source = makeBundleSource(context, config.source) + WvbAndroid.initialize(context) + val source = makeSource(context, config.source) var remote: Remote? = null var updater: Updater? = null val registered = mutableListOf() try { config.updater?.let { updaterConfig -> - val createdRemote = Remote(updaterConfig.remote.endpoint) + val createdRemote = Remote(updaterConfig.remote.baseUrl, updaterConfig.remote.options) remote = createdRemote // assign before Updater(), so a throw there still closes it updater = Updater( source, createdRemote, + updaterConfig.updateFilepath ?: java.io.File( + config.source.remoteDir ?: defaultRemoteDir(context), "update.json" + ).absolutePath, UpdaterOptions( channel = updaterConfig.channel, - integrity = updaterConfig.integrityPolicy?.let { - UpdaterIntegrityOptions(policy = it) - }, - signature = updaterConfig.signatureVerifier?.let { - UpdaterSignatureOptions(verify = SignatureVerification.Key(it)) - }, + integrity = updaterConfig.integrity, + signature = updaterConfig.signature, ), ) } diff --git a/lib/src/main/kotlin/dev/wvb/WebViewBundleBridge.kt b/lib/src/main/kotlin/dev/wvb/WebViewBundleBridge.kt index b9f81b9..78d2241 100644 --- a/lib/src/main/kotlin/dev/wvb/WebViewBundleBridge.kt +++ b/lib/src/main/kotlin/dev/wvb/WebViewBundleBridge.kt @@ -2,9 +2,7 @@ package dev.wvb import org.json.JSONArray -/** - * Bridges to communicate with the WebView. - */ +/** Commands and payloads match @wvb/bridge's source, remote, and updater APIs. */ internal class WebViewBundleBridge(private val wvb: WebViewBundle) : BridgeHandlers { override fun register(bridge: Bridge) { registerSource(bridge) @@ -14,111 +12,137 @@ internal class WebViewBundleBridge(private val wvb: WebViewBundle) : BridgeHandl private fun registerSource(bridge: Bridge) { val source = wvb.source - bridge.handler("sourceListBundles") { JSONArray(source.listBundles().map { it.toJson() }) } - bridge.handler("sourceLoadVersion") { params -> - source.loadVersion(BridgeCodec.params(params).requireString("bundleName"))?.toJson() + bridge.handler("sourceListBundles") { + JSONArray(source.listBundles().map { it.toJson() }) } - bridge.handler("sourceUpdateVersion") { params -> + bridge.handler("sourceListBuiltinBundles") { + JSONArray(source.listBuiltinBundles().map { it.toJson() }) + } + bridge.handler("sourceListRemoteBundles") { + JSONArray(source.listRemoteBundles().map { it.toJson() }) + } + bridge.handler("sourceGetVersion") { params -> val p = BridgeCodec.params(params) - source.updateVersion(p.requireString("bundleName"), p.requireString("version")) - null + source.getVersion(p.requireString("bundleName"))?.toJson() + } + bridge.handler("sourceGetRemoteStagedVersion") { params -> + val p = BridgeCodec.params(params) + source.getRemoteStagedVersion(p.requireString("bundleName")) + } + bridge.handler("sourceGetRemotePreviousVersion") { params -> + val p = BridgeCodec.params(params) + source.getRemotePreviousVersion(p.requireString("bundleName")) } bridge.handler("sourceResolveFilepath") { params -> - source.resolveFilepath(BridgeCodec.params(params).requireString("bundleName")) + val p = BridgeCodec.params(params) + source.resolveFilepath(p.requireString("bundleName")) + } + bridge.handler("sourceUnload") { params -> + val p = BridgeCodec.params(params) + source.unload(p.requireString("bundleName")) } bridge.handler("sourceGetBuiltinBundleFilepath") { params -> val p = BridgeCodec.params(params) - source.getBuiltinBundleFilepath( - p.requireString("bundleName"), p.requireString("version") - ) + source.getBuiltinBundleFilepath(p.requireString("bundleName"), p.requireString("version")) } bridge.handler("sourceGetRemoteBundleFilepath") { params -> val p = BridgeCodec.params(params) - source.getRemoteBundleFilepath( - p.requireString("bundleName"), p.requireString("version") - ) + source.getRemoteBundleFilepath(p.requireString("bundleName"), p.requireString("version")) + } + bridge.handler("sourceGetBuiltinVersionData") { params -> + val p = BridgeCodec.params(params) + source.getBuiltinVersionData(p.requireString("bundleName"), p.requireString("version"))?.toJson() + } + bridge.handler("sourceGetRemoteVersionData") { params -> + val p = BridgeCodec.params(params) + source.getRemoteVersionData(p.requireString("bundleName"), p.requireString("version"))?.toJson() + } + bridge.handler("sourceUpdateRemoteVersion") { params -> + val p = BridgeCodec.params(params) + source.updateRemoteVersion(p.requireString("bundleName"), p.requireString("version")).toJson() + } + bridge.handler("sourceUpdateRemoteVersions") { params -> + val p = BridgeCodec.params(params) + JSONArray(source.updateRemoteVersions(p.requireObject("items").stringMap()).map { it.toJson() }) } - bridge.handler("sourceLoadBuiltinMetadata") { params -> + bridge.handler("sourceStageRemoteBundle") { params -> val p = BridgeCodec.params(params) - source.loadBuiltinMetadata(p.requireString("bundleName"), p.requireString("version")) - ?.toJson() + source.stageRemoteBundle(p.requireString("bundleName"), p.requireObject("data").stageData()).toJson() } - bridge.handler("sourceLoadRemoteMetadata") { params -> + bridge.handler("sourceStageRemoteBundles") { params -> val p = BridgeCodec.params(params) - source.loadRemoteMetadata(p.requireString("bundleName"), p.requireString("version")) - ?.toJson() + JSONArray(source.stageRemoteBundles(p.requireObject("items").mapValues { obj, key -> obj.requireObject(key).stageData() }).map { it.toJson() }) } - bridge.handler("sourceUnloadDescriptor") { params -> - source.unloadDescriptor(BridgeCodec.params(params).requireString("bundleName")) + bridge.handler("sourceRemoveRemoteBundles") { params -> + val p = BridgeCodec.params(params) + JSONArray(source.removeRemoteBundles(p.requireObject("items").mapValues { obj, key -> obj.requireObject(key).removeData() }).map { it.toJson() }) } bridge.handler("sourceRemoveRemoteBundle") { params -> val p = BridgeCodec.params(params) - source.removeRemoteBundle(p.requireString("bundleName"), p.requireString("version")) + source.removeRemoteBundle(p.requireString("bundleName"), p.requireString("version"), p.optionalBoolean("force")).toJson() } - bridge.handler("sourceRemoteRetainedVersions") { params -> - source.remoteRetainedVersions(BridgeCodec.params(params).requireString("bundleName")) + bridge.handler("sourcePruneRemoteBundle") { params -> + val p = BridgeCodec.params(params) + source.pruneRemoteBundle(p.requireString("bundleName")).toJson() } bridge.handler("sourcePruneRemoteBundles") { params -> - source.pruneRemoteBundles(BridgeCodec.params(params).requireString("bundleName")) + val p = BridgeCodec.params(params) + JSONArray(source.pruneRemoteBundles(p.requireArray("bundleNames").strings()).map { it.toJson() }) } } private fun registerRemote(bridge: Bridge) { - bridge.handler("remoteListBundles") { params -> - val channel = BridgeCodec.params(params).optionalString("channel") - JSONArray( - requireRemote().listBundles(RemoteFetchOptions(channel = channel)) - .map { it.toJson() }, - ) - } - bridge.handler("remoteGetInfo") { params -> - val p = BridgeCodec.params(params) - requireRemote().getInfo( - p.requireString("bundleName"), - RemoteFetchOptions(channel = p.optionalString("channel")), - ).toJson() + bridge.handler("remoteGetUpdate") { params -> + val options = BridgeCodec.params(params).optionalObject("options") + requireRemote().getUpdate(options?.let { + RemoteGetUpdateOptions(etag = it.optionalString("etag"), channel = it.optionalString("channel")) + })?.toJson() } bridge.handler("remoteDownload") { params -> val p = BridgeCodec.params(params) - requireRemote().download( - p.requireString("bundleName"), p.optionalString("channel") - ).info.toJson() - } - bridge.handler("remoteDownloadVersion") { params -> - val p = BridgeCodec.params(params) - requireRemote().downloadVersion( - p.requireString("bundleName"), p.requireString("version") - ).info.toJson() + requireRemote().download(p.requireString("url"), p.requireString("filepath")) + null } } private fun registerUpdater(bridge: Bridge) { - bridge.handler("updaterListRemotes") { - JSONArray( - requireUpdater().listRemotes().map { it.toJson() }) - } bridge.handler("updaterGetUpdate") { params -> - requireUpdater().getUpdate(BridgeCodec.params(params).requireString("bundleName")) - .toJson() + val options = BridgeCodec.params(params).optionalObject("options") + requireUpdater().getUpdate(options?.let { + UpdaterGetUpdateOptions(expectSignatureKeyId = it.optionalString("expectSignatureKeyId")) + })?.toJson() } bridge.handler("updaterDownload") { params -> val p = BridgeCodec.params(params) - requireUpdater().downloadUpdate( - p.requireString("bundleName"), p.optionalString("version") - ).toJson() + val options = p.optionalObject("options")?.let { + UpdaterDownloadOptions( + concurrency = it.optionalUnsigned("concurrency", UInt.MAX_VALUE.toULong())?.toUInt(), + timeout = it.optionalUnsigned("timeout"), + ) + } + JSONArray(requireUpdater().download( + p.requireArray("bundleUpdates").objects { it.bundleUpdate() }, options, + ).map { it.toJson() }) } bridge.handler("updaterInstall") { params -> - val p = BridgeCodec.params(params) - requireUpdater().install(p.requireString("bundleName"), p.requireString("version")) - null + val targets = BridgeCodec.params(params).requireArray("targets").objects { + UpdaterInstallTarget(name = it.requireString("name"), version = it.optionalString("version")) + } + JSONArray(requireUpdater().install(targets).map { it.toJson() }) + } + bridge.handler("updaterRollback") { params -> + val targets = BridgeCodec.params(params).requireArray("targets").objects { + UpdaterRollbackTarget(name = it.requireString("name"), version = it.optionalString("version")) + } + JSONArray(requireUpdater().rollback(targets).map { it.toJson() }) } } private fun requireRemote(): Remote = wvb.remote ?: throw BridgeError( - code = "remote_not_initialized", message = "remote is not initialized." + code = "remote_not_initialized", message = "remote is not initialized.", ) private fun requireUpdater(): Updater = wvb.updater ?: throw BridgeError( - code = "updater_not_initialized", message = "updater is not initialized." + code = "updater_not_initialized", message = "updater is not initialized.", ) } diff --git a/lib/src/main/kotlin/dev/wvb/wvb_ffi.kt b/lib/src/main/kotlin/dev/wvb/WvbFFI.kt similarity index 78% rename from lib/src/main/kotlin/dev/wvb/wvb_ffi.kt rename to lib/src/main/kotlin/dev/wvb/WvbFFI.kt index d7105ec..2866547 100644 --- a/lib/src/main/kotlin/dev/wvb/wvb_ffi.kt +++ b/lib/src/main/kotlin/dev/wvb/WvbFFI.kt @@ -30,6 +30,8 @@ import java.nio.CharBuffer import java.nio.charset.CodingErrorAction import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.ConcurrentHashMap +import android.os.Build +import androidx.annotation.RequiresApi import java.util.concurrent.atomic.AtomicBoolean import kotlin.coroutines.resume import kotlinx.coroutines.CancellableContinuation @@ -620,37 +622,15 @@ internal open class UniffiForeignFutureResultVoid( internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback { fun callback(`callbackData`: Long,`result`: UniffiForeignFutureResultVoid.UniffiByValue,) } -internal interface UniffiCallbackInterfaceIntegrityCheckMethod0 : com.sun.jna.Callback { - fun callback(`uniffiHandle`: Long,`data`: RustBuffer.ByValue,`integrity`: RustBuffer.ByValue,`uniffiFutureCallback`: UniffiForeignFutureCompleteI8,`uniffiCallbackData`: Long,`uniffiOutDroppedCallback`: UniffiForeignFutureDroppedCallbackStruct,) -} internal interface UniffiCallbackInterfaceProxyResolverMethod0 : com.sun.jna.Callback { fun callback(`uniffiHandle`: Long,`uri`: RustBuffer.ByValue,`uniffiFutureCallback`: UniffiForeignFutureCompleteRustBuffer,`uniffiCallbackData`: Long,`uniffiOutDroppedCallback`: UniffiForeignFutureDroppedCallbackStruct,) } internal interface UniffiCallbackInterfaceRemoteOnDownloadMethod0 : com.sun.jna.Callback { fun callback(`uniffiHandle`: Long,`data`: RustBuffer.ByValue,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) } -internal interface UniffiCallbackInterfaceSignatureVerifyMethod0 : com.sun.jna.Callback { +internal interface UniffiCallbackInterfaceSignatureCustomVerifyMethod0 : com.sun.jna.Callback { fun callback(`uniffiHandle`: Long,`message`: RustBuffer.ByValue,`signature`: RustBuffer.ByValue,`uniffiFutureCallback`: UniffiForeignFutureCompleteI8,`uniffiCallbackData`: Long,`uniffiOutDroppedCallback`: UniffiForeignFutureDroppedCallbackStruct,) } -@Structure.FieldOrder("uniffiFree", "uniffiClone", "check") -internal open class UniffiVTableCallbackInterfaceIntegrityCheck( - @JvmField internal var `uniffiFree`: UniffiCallbackInterfaceFree? = null, - @JvmField internal var `uniffiClone`: UniffiCallbackInterfaceClone? = null, - @JvmField internal var `check`: UniffiCallbackInterfaceIntegrityCheckMethod0? = null, -) : Structure() { - class UniffiByValue( - `uniffiFree`: UniffiCallbackInterfaceFree? = null, - `uniffiClone`: UniffiCallbackInterfaceClone? = null, - `check`: UniffiCallbackInterfaceIntegrityCheckMethod0? = null, - ): UniffiVTableCallbackInterfaceIntegrityCheck(`uniffiFree`,`uniffiClone`,`check`,), Structure.ByValue - - internal fun uniffiSetValue(other: UniffiVTableCallbackInterfaceIntegrityCheck) { - `uniffiFree` = other.`uniffiFree` - `uniffiClone` = other.`uniffiClone` - `check` = other.`check` - } - -} @Structure.FieldOrder("uniffiFree", "uniffiClone", "resolve") internal open class UniffiVTableCallbackInterfaceProxyResolver( @JvmField internal var `uniffiFree`: UniffiCallbackInterfaceFree? = null, @@ -690,18 +670,18 @@ internal open class UniffiVTableCallbackInterfaceRemoteOnDownload( } @Structure.FieldOrder("uniffiFree", "uniffiClone", "verify") -internal open class UniffiVTableCallbackInterfaceSignatureVerify( +internal open class UniffiVTableCallbackInterfaceSignatureCustomVerify( @JvmField internal var `uniffiFree`: UniffiCallbackInterfaceFree? = null, @JvmField internal var `uniffiClone`: UniffiCallbackInterfaceClone? = null, - @JvmField internal var `verify`: UniffiCallbackInterfaceSignatureVerifyMethod0? = null, + @JvmField internal var `verify`: UniffiCallbackInterfaceSignatureCustomVerifyMethod0? = null, ) : Structure() { class UniffiByValue( `uniffiFree`: UniffiCallbackInterfaceFree? = null, `uniffiClone`: UniffiCallbackInterfaceClone? = null, - `verify`: UniffiCallbackInterfaceSignatureVerifyMethod0? = null, - ): UniffiVTableCallbackInterfaceSignatureVerify(`uniffiFree`,`uniffiClone`,`verify`,), Structure.ByValue + `verify`: UniffiCallbackInterfaceSignatureCustomVerifyMethod0? = null, + ): UniffiVTableCallbackInterfaceSignatureCustomVerify(`uniffiFree`,`uniffiClone`,`verify`,), Structure.ByValue - internal fun uniffiSetValue(other: UniffiVTableCallbackInterfaceSignatureVerify) { + internal fun uniffiSetValue(other: UniffiVTableCallbackInterfaceSignatureCustomVerify) { `uniffiFree` = other.`uniffiFree` `uniffiClone` = other.`uniffiClone` `verify` = other.`verify` @@ -739,6 +719,14 @@ internal object IntegrityCheckingUniffiLib { ): Short external fun uniffi_wvb_ffi_checksum_func_write_bundle_to_bytes( ): Short + external fun uniffi_wvb_ffi_checksum_func_extension( + ): Short + external fun uniffi_wvb_ffi_checksum_func_mime_type( + ): Short + external fun uniffi_wvb_ffi_checksum_func_runtime_version( + ): Short + external fun uniffi_wvb_ffi_checksum_func_update_protocol_version( + ): Short external fun uniffi_wvb_ffi_checksum_method_bundle_descriptor( ): Short external fun uniffi_wvb_ffi_checksum_method_bundle_get_data( @@ -787,14 +775,16 @@ internal object IntegrityCheckingUniffiLib { ): Short external fun uniffi_wvb_ffi_checksum_method_index_get_entry( ): Short + external fun uniffi_wvb_ffi_checksum_method_cancellation_cancel( + ): Short + external fun uniffi_wvb_ffi_checksum_method_cancellation_is_cancelled( + ): Short external fun uniffi_wvb_ffi_checksum_method_integrity_serialize( ): Short external fun uniffi_wvb_ffi_checksum_method_integrity_validate( ): Short external fun uniffi_wvb_ffi_checksum_method_integrity_value( ): Short - external fun uniffi_wvb_ffi_checksum_method_integritycheck_check( - ): Short external fun uniffi_wvb_ffi_checksum_method_bundleprotocolhandler_handle( ): Short external fun uniffi_wvb_ffi_checksum_method_proxyprotocolhandler_handle( @@ -803,68 +793,80 @@ internal object IntegrityCheckingUniffiLib { ): Short external fun uniffi_wvb_ffi_checksum_method_remote_download( ): Short - external fun uniffi_wvb_ffi_checksum_method_remote_download_version( + external fun uniffi_wvb_ffi_checksum_method_remote_get_update( ): Short - external fun uniffi_wvb_ffi_checksum_method_remote_get_info( + external fun uniffi_wvb_ffi_checksum_method_remoteondownload_on_download( ): Short - external fun uniffi_wvb_ffi_checksum_method_remote_list_bundles( + external fun uniffi_wvb_ffi_checksum_method_signaturecustomverify_verify( ): Short - external fun uniffi_wvb_ffi_checksum_method_remoteondownload_on_download( + external fun uniffi_wvb_ffi_checksum_method_loadeddescriptor_descriptor( + ): Short + external fun uniffi_wvb_ffi_checksum_method_loadeddescriptor_get_data( ): Short - external fun uniffi_wvb_ffi_checksum_method_signatureverify_verify( + external fun uniffi_wvb_ffi_checksum_method_loadeddescriptor_get_data_checksum( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_fetch_builtin_bundle( + external fun uniffi_wvb_ffi_checksum_method_source_fetch_builtin_bundle( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_fetch_bundle( + external fun uniffi_wvb_ffi_checksum_method_source_fetch_bundle( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_fetch_descriptor( + external fun uniffi_wvb_ffi_checksum_method_source_fetch_descriptor( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_fetch_remote_bundle( + external fun uniffi_wvb_ffi_checksum_method_source_fetch_remote_bundle( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_get_builtin_bundle_filepath( + external fun uniffi_wvb_ffi_checksum_method_source_get_builtin_bundle_filepath( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_get_remote_bundle_filepath( + external fun uniffi_wvb_ffi_checksum_method_source_get_builtin_version_data( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_list_bundles( + external fun uniffi_wvb_ffi_checksum_method_source_get_remote_bundle_filepath( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_load_builtin_metadata( + external fun uniffi_wvb_ffi_checksum_method_source_get_remote_previous_version( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_load_descriptor( + external fun uniffi_wvb_ffi_checksum_method_source_get_remote_staged_version( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_load_remote_metadata( + external fun uniffi_wvb_ffi_checksum_method_source_get_remote_version_data( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_load_version( + external fun uniffi_wvb_ffi_checksum_method_source_get_version( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_prune_remote_bundles( + external fun uniffi_wvb_ffi_checksum_method_source_list_builtin_bundles( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_remote_retained_versions( + external fun uniffi_wvb_ffi_checksum_method_source_list_bundles( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_remove_remote_bundle( + external fun uniffi_wvb_ffi_checksum_method_source_list_remote_bundles( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_resolve_filepath( + external fun uniffi_wvb_ffi_checksum_method_source_load( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_unload_descriptor( + external fun uniffi_wvb_ffi_checksum_method_source_prune_remote_bundle( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_update_version( + external fun uniffi_wvb_ffi_checksum_method_source_prune_remote_bundles( ): Short - external fun uniffi_wvb_ffi_checksum_method_bundlesource_write_remote_bundle( + external fun uniffi_wvb_ffi_checksum_method_source_remove_remote_bundle( ): Short - external fun uniffi_wvb_ffi_checksum_method_loadeddescriptor_descriptor( + external fun uniffi_wvb_ffi_checksum_method_source_remove_remote_bundles( ): Short - external fun uniffi_wvb_ffi_checksum_method_loadeddescriptor_get_data( + external fun uniffi_wvb_ffi_checksum_method_source_resolve_filepath( ): Short - external fun uniffi_wvb_ffi_checksum_method_loadeddescriptor_get_data_checksum( + external fun uniffi_wvb_ffi_checksum_method_source_stage_remote_bundle( + ): Short + external fun uniffi_wvb_ffi_checksum_method_source_stage_remote_bundles( + ): Short + external fun uniffi_wvb_ffi_checksum_method_source_unload( + ): Short + external fun uniffi_wvb_ffi_checksum_method_source_update_remote_version( ): Short - external fun uniffi_wvb_ffi_checksum_method_updater_download_update( + external fun uniffi_wvb_ffi_checksum_method_source_update_remote_versions( + ): Short + external fun uniffi_wvb_ffi_checksum_method_updater_download( ): Short external fun uniffi_wvb_ffi_checksum_method_updater_get_update( ): Short external fun uniffi_wvb_ffi_checksum_method_updater_install( ): Short - external fun uniffi_wvb_ffi_checksum_method_updater_list_remotes( + external fun uniffi_wvb_ffi_checksum_method_updater_rollback( ): Short external fun uniffi_wvb_ffi_checksum_constructor_bundlebuilder_new( ): Short + external fun uniffi_wvb_ffi_checksum_constructor_cancellation_new( + ): Short external fun uniffi_wvb_ffi_checksum_constructor_integrity_compute( ): Short external fun uniffi_wvb_ffi_checksum_constructor_integrity_parse( @@ -877,7 +879,7 @@ internal object IntegrityCheckingUniffiLib { ): Short external fun uniffi_wvb_ffi_checksum_constructor_remote_new( ): Short - external fun uniffi_wvb_ffi_checksum_constructor_bundlesource_new( + external fun uniffi_wvb_ffi_checksum_constructor_source_new( ): Short external fun uniffi_wvb_ffi_checksum_constructor_updater_new( ): Short @@ -897,10 +899,9 @@ internal object UniffiLib { init { Native.register(UniffiLib::class.java, findLibraryName(componentName = "wvb_ffi")) - uniffiCallbackInterfaceIntegrityCheck.register(this) uniffiCallbackInterfaceProxyResolver.register(this) uniffiCallbackInterfaceRemoteOnDownload.register(this) - uniffiCallbackInterfaceSignatureVerify.register(this) + uniffiCallbackInterfaceSignatureCustomVerify.register(this) } external fun uniffi_wvb_ffi_fn_clone_bundle(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, @@ -973,6 +974,16 @@ external fun uniffi_wvb_ffi_fn_method_index_entries(`ptr`: Long,uniffi_out_err: ): RustBuffer.ByValue external fun uniffi_wvb_ffi_fn_method_index_get_entry(`ptr`: Long,`path`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue +external fun uniffi_wvb_ffi_fn_clone_cancellation(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, +): Long +external fun uniffi_wvb_ffi_fn_free_cancellation(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, +): Unit +external fun uniffi_wvb_ffi_fn_constructor_cancellation_new(uniffi_out_err: UniffiRustCallStatus, +): Long +external fun uniffi_wvb_ffi_fn_method_cancellation_cancel(`ptr`: Long,uniffi_out_err: UniffiRustCallStatus, +): Unit +external fun uniffi_wvb_ffi_fn_method_cancellation_is_cancelled(`ptr`: Long,uniffi_out_err: UniffiRustCallStatus, +): Byte external fun uniffi_wvb_ffi_fn_clone_integrity(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Long external fun uniffi_wvb_ffi_fn_free_integrity(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, @@ -987,14 +998,6 @@ external fun uniffi_wvb_ffi_fn_method_integrity_validate(`ptr`: Long,`data`: Rus ): Byte external fun uniffi_wvb_ffi_fn_method_integrity_value(`ptr`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue -external fun uniffi_wvb_ffi_fn_clone_integritycheck(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Long -external fun uniffi_wvb_ffi_fn_free_integritycheck(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Unit -external fun uniffi_wvb_ffi_fn_init_callback_vtable_integritycheck(`vtable`: UniffiVTableCallbackInterfaceIntegrityCheck, -): Unit -external fun uniffi_wvb_ffi_fn_method_integritycheck_check(`ptr`: Long,`data`: RustBuffer.ByValue,`integrity`: RustBuffer.ByValue, -): Long external fun uniffi_wvb_ffi_fn_clone_bundleprotocolhandler(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Long external fun uniffi_wvb_ffi_fn_free_bundleprotocolhandler(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, @@ -1025,15 +1028,11 @@ external fun uniffi_wvb_ffi_fn_clone_remote(`handle`: Long,uniffi_out_err: Uniff ): Long external fun uniffi_wvb_ffi_fn_free_remote(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Unit -external fun uniffi_wvb_ffi_fn_constructor_remote_new(`endpoint`: RustBuffer.ByValue,`options`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Long -external fun uniffi_wvb_ffi_fn_method_remote_download(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`channel`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_constructor_remote_new(`baseUrl`: RustBuffer.ByValue,`options`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Long -external fun uniffi_wvb_ffi_fn_method_remote_download_version(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_remote_download(`ptr`: Long,`url`: RustBuffer.ByValue,`filepath`: RustBuffer.ByValue,`cancellation`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_remote_get_info(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`options`: RustBuffer.ByValue, -): Long -external fun uniffi_wvb_ffi_fn_method_remote_list_bundles(`ptr`: Long,`options`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_remote_get_update(`ptr`: Long,`options`: RustBuffer.ByValue, ): Long external fun uniffi_wvb_ffi_fn_clone_remoteondownload(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Long @@ -1043,79 +1042,93 @@ external fun uniffi_wvb_ffi_fn_init_callback_vtable_remoteondownload(`vtable`: U ): Unit external fun uniffi_wvb_ffi_fn_method_remoteondownload_on_download(`ptr`: Long,`data`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Unit -external fun uniffi_wvb_ffi_fn_clone_signatureverify(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, +external fun uniffi_wvb_ffi_fn_clone_signaturecustomverify(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Long -external fun uniffi_wvb_ffi_fn_free_signatureverify(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, +external fun uniffi_wvb_ffi_fn_free_signaturecustomverify(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, +): Unit +external fun uniffi_wvb_ffi_fn_init_callback_vtable_signaturecustomverify(`vtable`: UniffiVTableCallbackInterfaceSignatureCustomVerify, ): Unit -external fun uniffi_wvb_ffi_fn_init_callback_vtable_signatureverify(`vtable`: UniffiVTableCallbackInterfaceSignatureVerify, +external fun uniffi_wvb_ffi_fn_method_signaturecustomverify_verify(`ptr`: Long,`message`: RustBuffer.ByValue,`signature`: RustBuffer.ByValue, +): Long +external fun uniffi_wvb_ffi_fn_clone_loadeddescriptor(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, +): Long +external fun uniffi_wvb_ffi_fn_free_loadeddescriptor(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Unit -external fun uniffi_wvb_ffi_fn_method_signatureverify_verify(`ptr`: Long,`message`: RustBuffer.ByValue,`signature`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_loadeddescriptor_descriptor(`ptr`: Long,uniffi_out_err: UniffiRustCallStatus, +): Long +external fun uniffi_wvb_ffi_fn_method_loadeddescriptor_get_data(`ptr`: Long,`path`: RustBuffer.ByValue, +): Long +external fun uniffi_wvb_ffi_fn_method_loadeddescriptor_get_data_checksum(`ptr`: Long,`path`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_clone_bundlesource(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, +external fun uniffi_wvb_ffi_fn_clone_source(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Long -external fun uniffi_wvb_ffi_fn_free_bundlesource(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, +external fun uniffi_wvb_ffi_fn_free_source(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Unit -external fun uniffi_wvb_ffi_fn_constructor_bundlesource_new(`config`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +external fun uniffi_wvb_ffi_fn_constructor_source_new(`config`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_fetch_builtin_bundle(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_fetch_builtin_bundle(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_fetch_bundle(`ptr`: Long,`bundleName`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_fetch_bundle(`ptr`: Long,`bundleName`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_fetch_descriptor(`ptr`: Long,`bundleName`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_fetch_descriptor(`ptr`: Long,`bundleName`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_fetch_remote_bundle(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_fetch_remote_bundle(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_get_builtin_bundle_filepath(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +external fun uniffi_wvb_ffi_fn_method_source_get_builtin_bundle_filepath(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue -external fun uniffi_wvb_ffi_fn_method_bundlesource_get_remote_bundle_filepath(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +external fun uniffi_wvb_ffi_fn_method_source_get_builtin_version_data(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, +): Long +external fun uniffi_wvb_ffi_fn_method_source_get_remote_bundle_filepath(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue -external fun uniffi_wvb_ffi_fn_method_bundlesource_list_bundles(`ptr`: Long, +external fun uniffi_wvb_ffi_fn_method_source_get_remote_previous_version(`ptr`: Long,`bundleName`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_load_builtin_metadata(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_get_remote_staged_version(`ptr`: Long,`bundleName`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_load_descriptor(`ptr`: Long,`bundleName`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_get_remote_version_data(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_load_remote_metadata(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_get_version(`ptr`: Long,`bundleName`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_load_version(`ptr`: Long,`bundleName`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_list_builtin_bundles(`ptr`: Long, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_prune_remote_bundles(`ptr`: Long,`bundleName`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_list_bundles(`ptr`: Long, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_remote_retained_versions(`ptr`: Long,`bundleName`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_list_remote_bundles(`ptr`: Long, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_remove_remote_bundle(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_load(`ptr`: Long,`bundleName`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_resolve_filepath(`ptr`: Long,`bundleName`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_prune_remote_bundle(`ptr`: Long,`bundleName`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_unload_descriptor(`ptr`: Long,`bundleName`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, -): Byte -external fun uniffi_wvb_ffi_fn_method_bundlesource_update_version(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_prune_remote_bundles(`ptr`: Long,`bundleNames`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_bundlesource_write_remote_bundle(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue,`bundle`: Long,`metadata`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_remove_remote_bundle(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue,`force`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_clone_loadeddescriptor(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, +external fun uniffi_wvb_ffi_fn_method_source_remove_remote_bundles(`ptr`: Long,`items`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_free_loadeddescriptor(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, -): Unit -external fun uniffi_wvb_ffi_fn_method_loadeddescriptor_descriptor(`ptr`: Long,uniffi_out_err: UniffiRustCallStatus, +external fun uniffi_wvb_ffi_fn_method_source_resolve_filepath(`ptr`: Long,`bundleName`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_loadeddescriptor_get_data(`ptr`: Long,`path`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_stage_remote_bundle(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`data`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_loadeddescriptor_get_data_checksum(`ptr`: Long,`path`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_source_stage_remote_bundles(`ptr`: Long,`items`: RustBuffer.ByValue, +): Long +external fun uniffi_wvb_ffi_fn_method_source_unload(`ptr`: Long,`bundleName`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +): Byte +external fun uniffi_wvb_ffi_fn_method_source_update_remote_version(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, +): Long +external fun uniffi_wvb_ffi_fn_method_source_update_remote_versions(`ptr`: Long,`items`: RustBuffer.ByValue, ): Long external fun uniffi_wvb_ffi_fn_clone_updater(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Long external fun uniffi_wvb_ffi_fn_free_updater(`handle`: Long,uniffi_out_err: UniffiRustCallStatus, ): Unit -external fun uniffi_wvb_ffi_fn_constructor_updater_new(`source`: Long,`remote`: Long,`options`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, +external fun uniffi_wvb_ffi_fn_constructor_updater_new(`source`: Long,`remote`: Long,`updateFilepath`: RustBuffer.ByValue,`options`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): Long -external fun uniffi_wvb_ffi_fn_method_updater_download_update(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_updater_download(`ptr`: Long,`bundleUpdates`: RustBuffer.ByValue,`options`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_updater_get_update(`ptr`: Long,`bundleName`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_updater_get_update(`ptr`: Long,`options`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_updater_install(`ptr`: Long,`bundleName`: RustBuffer.ByValue,`version`: RustBuffer.ByValue, +external fun uniffi_wvb_ffi_fn_method_updater_install(`ptr`: Long,`targets`: RustBuffer.ByValue, ): Long -external fun uniffi_wvb_ffi_fn_method_updater_list_remotes(`ptr`: Long, +external fun uniffi_wvb_ffi_fn_method_updater_rollback(`ptr`: Long,`targets`: RustBuffer.ByValue, ): Long external fun uniffi_wvb_ffi_fn_func_read_bundle(`filepath`: RustBuffer.ByValue, ): Long @@ -1125,6 +1138,14 @@ external fun uniffi_wvb_ffi_fn_func_write_bundle(`bundle`: Long,`filepath`: Rust ): Long external fun uniffi_wvb_ffi_fn_func_write_bundle_to_bytes(`bundle`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue +external fun uniffi_wvb_ffi_fn_func_extension(uniffi_out_err: UniffiRustCallStatus, +): RustBuffer.ByValue +external fun uniffi_wvb_ffi_fn_func_mime_type(uniffi_out_err: UniffiRustCallStatus, +): RustBuffer.ByValue +external fun uniffi_wvb_ffi_fn_func_runtime_version(uniffi_out_err: UniffiRustCallStatus, +): Byte +external fun uniffi_wvb_ffi_fn_func_update_protocol_version(uniffi_out_err: UniffiRustCallStatus, +): RustBuffer.ByValue external fun ffi_wvb_ffi_rustbuffer_alloc(`size`: Long,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue external fun ffi_wvb_ffi_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,uniffi_out_err: UniffiRustCallStatus, @@ -1256,6 +1277,18 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_wvb_ffi_checksum_func_write_bundle_to_bytes() != 60094.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_wvb_ffi_checksum_func_extension() != 30907.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_wvb_ffi_checksum_func_mime_type() != 22305.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_wvb_ffi_checksum_func_runtime_version() != 51343.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_wvb_ffi_checksum_func_update_protocol_version() != 24855.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_wvb_ffi_checksum_method_bundle_descriptor() != 24504.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -1328,6 +1361,12 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_wvb_ffi_checksum_method_index_get_entry() != 50953.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (lib.uniffi_wvb_ffi_checksum_method_cancellation_cancel() != 13086.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_wvb_ffi_checksum_method_cancellation_is_cancelled() != 6967.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (lib.uniffi_wvb_ffi_checksum_method_integrity_serialize() != 62469.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -1337,9 +1376,6 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_wvb_ffi_checksum_method_integrity_value() != 613.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_integritycheck_check() != 15325.toShort()) { - throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - } if (lib.uniffi_wvb_ffi_checksum_method_bundleprotocolhandler_handle() != 38322.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -1349,109 +1385,127 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_wvb_ffi_checksum_method_proxyresolver_resolve() != 3972.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_remote_download() != 21588.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_remote_download() != 26520.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_remote_download_version() != 8652.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_remote_get_update() != 30874.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_remote_get_info() != 26038.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_remoteondownload_on_download() != 24193.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_remote_list_bundles() != 46632.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_signaturecustomverify_verify() != 33505.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_remoteondownload_on_download() != 62542.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_loadeddescriptor_descriptor() != 52553.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_signatureverify_verify() != 61012.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_loadeddescriptor_get_data() != 42308.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_fetch_builtin_bundle() != 46850.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_loadeddescriptor_get_data_checksum() != 3423.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_fetch_bundle() != 3805.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_fetch_builtin_bundle() != 17435.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_fetch_descriptor() != 51584.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_fetch_bundle() != 44562.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_fetch_remote_bundle() != 65226.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_fetch_descriptor() != 51197.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_get_builtin_bundle_filepath() != 24323.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_fetch_remote_bundle() != 43833.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_get_remote_bundle_filepath() != 7311.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_get_builtin_bundle_filepath() != 33416.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_list_bundles() != 57264.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_get_builtin_version_data() != 36382.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_load_builtin_metadata() != 45714.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_get_remote_bundle_filepath() != 26863.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_load_descriptor() != 38145.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_get_remote_previous_version() != 56770.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_load_remote_metadata() != 53479.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_get_remote_staged_version() != 11049.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_load_version() != 12691.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_get_remote_version_data() != 64245.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_prune_remote_bundles() != 10982.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_get_version() != 13477.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_remote_retained_versions() != 40540.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_list_builtin_bundles() != 23719.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_remove_remote_bundle() != 28722.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_list_bundles() != 52967.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_resolve_filepath() != 59141.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_list_remote_bundles() != 47012.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_unload_descriptor() != 36116.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_load() != 63609.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_update_version() != 26121.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_prune_remote_bundle() != 21250.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_bundlesource_write_remote_bundle() != 31819.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_prune_remote_bundles() != 11241.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_loadeddescriptor_descriptor() != 52553.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_remove_remote_bundle() != 9597.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_loadeddescriptor_get_data() != 42308.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_remove_remote_bundles() != 53613.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_loadeddescriptor_get_data_checksum() != 3423.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_resolve_filepath() != 34868.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_wvb_ffi_checksum_method_source_stage_remote_bundle() != 34711.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_wvb_ffi_checksum_method_source_stage_remote_bundles() != 6972.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_wvb_ffi_checksum_method_source_unload() != 39693.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_updater_download_update() != 48197.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_update_remote_version() != 8467.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_updater_get_update() != 7181.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_source_update_remote_versions() != 46886.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_updater_install() != 17169.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_updater_download() != 27702.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_method_updater_list_remotes() != 43567.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_method_updater_get_update() != 56888.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_wvb_ffi_checksum_method_updater_install() != 12072.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_wvb_ffi_checksum_method_updater_rollback() != 19709.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_wvb_ffi_checksum_constructor_bundlebuilder_new() != 7081.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_constructor_integrity_compute() != 53699.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_constructor_cancellation_new() != 18611.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_constructor_integrity_parse() != 58850.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_constructor_integrity_compute() != 55661.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_constructor_bundleprotocolhandler_new() != 65404.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_constructor_integrity_parse() != 59952.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_wvb_ffi_checksum_constructor_bundleprotocolhandler_new() != 49457.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_wvb_ffi_checksum_constructor_proxyprotocolhandler_custom() != 21782.toShort()) { @@ -1460,13 +1514,13 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) { if (lib.uniffi_wvb_ffi_checksum_constructor_proxyprotocolhandler_new() != 17067.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_constructor_remote_new() != 63643.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_constructor_remote_new() != 1084.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_constructor_bundlesource_new() != 38494.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_constructor_source_new() != 4331.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_wvb_ffi_checksum_constructor_updater_new() != 63636.toShort()) { + if (lib.uniffi_wvb_ffi_checksum_constructor_updater_new() != 4993.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } } @@ -1760,32 +1814,55 @@ private class UniffiJnaCleanable( // using Android or not. // There are further runtime checks to chose the correct implementation // of the cleaner. + + private fun UniffiCleaner.Companion.create(): UniffiCleaner = - try { - // For safety's sake: if the library hasn't been run in android_cleaner = true - // mode, but is being run on Android, then we still need to think about - // Android API versions. - // So we check if java.lang.ref.Cleaner is there, and use that… - java.lang.Class.forName("java.lang.ref.Cleaner") - JavaLangRefCleaner() - } catch (e: ClassNotFoundException) { - // … otherwise, fallback to the JNA cleaner. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + AndroidSystemCleaner() + } else { UniffiJnaCleaner() } -private class JavaLangRefCleaner : UniffiCleaner { - val cleaner = java.lang.ref.Cleaner.create() +// The SystemCleaner, available from API Level 33. +// Some API Level 33 OSes do not support using it, so we require API Level 34. +@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) +private class AndroidSystemCleaner : UniffiCleaner { + val cleaner = android.system.SystemCleaner.cleaner() override fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable = - JavaLangRefCleanable(cleaner.register(value, cleanUpTask)) + AndroidSystemCleanable(cleaner.register(value, cleanUpTask)) } -private class JavaLangRefCleanable( - val cleanable: java.lang.ref.Cleaner.Cleanable +@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) +private class AndroidSystemCleanable( + private val cleanable: java.lang.ref.Cleaner.Cleanable, ) : UniffiCleaner.Cleanable { override fun clean() = cleanable.clean() } +/** + * @suppress + */ +public object FfiConverterUByte: FfiConverter { + override fun lift(value: Byte): UByte { + return value.toUByte() + } + + override fun read(buf: ByteBuffer): UByte { + return lift(buf.get()) + } + + override fun lower(value: UByte): Byte { + return value.toByte() + } + + override fun allocationSize(value: UByte) = 1UL + + override fun write(value: UByte, buf: ByteBuffer) { + buf.put(value.toByte()) + } +} + /** * @suppress */ @@ -3175,7 +3252,7 @@ public object FfiConverterTypeBundleDescriptor: FfiConverter UniffiLib.uniffi_wvb_ffi_fn_constructor_bundleprotocolhandler_new( - FfiConverterTypeBundleSource.lower(`source`),FfiConverterOptionalTypeBundleProtocolOptions.lower(`options`),_status) + FfiConverterTypeSource.lower(`source`),FfiConverterOptionalTypeBundleProtocolOptions.lower(`options`),_status) } ) @@ -3464,114 +3541,16 @@ public object FfiConverterTypeBundleProtocolHandler: FfiConverter - - /** - * Loads the manifest metadata for the builtin bundle `bundle_name` at `version`, - * or `None` if no such entry exists. - */ - suspend fun `loadBuiltinMetadata`(`bundleName`: kotlin.String, `version`: kotlin.String): BundleManifestMetadata? - - /** - * Loads (and caches) the descriptor for the current version of `bundle_name`. - * Concurrent calls for the same bundle share a single load (single-flight) and - * return the cached descriptor until the active version changes or - * [`unload_descriptor`](BundleSource::unload_descriptor) is called. - */ - suspend fun `loadDescriptor`(`bundleName`: kotlin.String): LoadedDescriptor - - /** - * Loads the manifest metadata for the remote bundle `bundle_name` at `version`, - * or `None` if no such entry exists. - */ - suspend fun `loadRemoteMetadata`(`bundleName`: kotlin.String, `version`: kotlin.String): BundleManifestMetadata? - - suspend fun `loadVersion`(`bundleName`: kotlin.String): BundleSourceVersion? - - /** - * Removes every staged remote version except the retained set (current and - * previous). Returns the versions that were removed. - */ - suspend fun `pruneRemoteBundles`(`bundleName`: kotlin.String): List - - /** - * Returns the remote versions that pruning retains (the current and previous). - */ - suspend fun `remoteRetainedVersions`(`bundleName`: kotlin.String): List - - /** - * Removes a single staged remote bundle version: drops its manifest entry and - * deletes its file from disk. Returns `true` if the entry existed. - */ - suspend fun `removeRemoteBundle`(`bundleName`: kotlin.String, `version`: kotlin.String): kotlin.Boolean - - suspend fun `resolveFilepath`(`bundleName`: kotlin.String): kotlin.String - - /** - * Drops the cached descriptor for `bundle_name`, if present. Already-returned - * [`LoadedDescriptor`] handles keep working; the next [`load_descriptor`] - * reloads from disk. Returns `true` if a cached descriptor was removed. - */ - fun `unloadDescriptor`(`bundleName`: kotlin.String): kotlin.Boolean +public interface CancellationInterface { - suspend fun `updateVersion`(`bundleName`: kotlin.String, `version`: kotlin.String) + fun `cancel`() - suspend fun `writeRemoteBundle`(`bundleName`: kotlin.String, `version`: kotlin.String, `bundle`: Bundle, `metadata`: BundleManifestMetadata) + fun `isCancelled`(): kotlin.Boolean companion object } -/** - * Unified access point for bundles from both the builtin and remote sources. - * - * The remote source takes precedence over the builtin source when both contain - * a bundle with the same name. - */ -open class BundleSource: Disposable, AutoCloseable, BundleSourceInterface +open class Cancellation: Disposable, AutoCloseable, CancellationInterface { @Suppress("UNUSED_PARAMETER") @@ -3595,12 +3574,12 @@ open class BundleSource: Disposable, AutoCloseable, BundleSourceInterface this.handle = 0 this.cleanable = null } - constructor(`config`: BundleSourceConfig) : + constructor() : this(UniffiWithHandle, - uniffiRustCallWithError(WebviewBundleException) { _status -> - UniffiLib.uniffi_wvb_ffi_fn_constructor_bundlesource_new( + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_constructor_cancellation_new( - FfiConverterTypeBundleSourceConfig.lower(`config`),_status) + _status) } ) @@ -3658,7 +3637,7 @@ open class BundleSource: Disposable, AutoCloseable, BundleSourceInterface return; } uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_bundlesource(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_free_cancellation(handle, status) } } } @@ -3671,372 +3650,317 @@ open class BundleSource: Disposable, AutoCloseable, BundleSourceInterface throw InternalException("uniffiCloneHandle() called on NoHandle object"); } return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_bundlesource(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_clone_cancellation(handle, status) } } + override fun `cancel`() + = + callWithHandle { + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_method_cancellation_cancel( + it, + _status) +} + } - /** - * Loads the full builtin bundle for `bundle_name` at `version`, bypassing the - * remote source and version resolution. - */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `fetchBuiltinBundle`(`bundleName`: kotlin.String, `version`: kotlin.String) : Bundle { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_fetch_builtin_bundle( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_u64(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_u64(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_u64(future) }, - // lift function - { FfiConverterTypeBundle.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, + + + override fun `isCancelled`(): kotlin.Boolean { + return FfiConverterBoolean.lift( + callWithHandle { + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_method_cancellation_is_cancelled( + it, + _status) +} + } ) } + - /** - * Loads the full bundle (header + index + data) for `bundle_name`. - */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `fetchBundle`(`bundleName`: kotlin.String) : Bundle { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_fetch_bundle( - uniffiHandle, - FfiConverterString.lower(`bundleName`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_u64(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_u64(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_u64(future) }, - // lift function - { FfiConverterTypeBundle.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) - } + + + + /** - * Loads only the header and index for `bundle_name`, skipping the data section. - * The returned descriptor does not support [`BundleDescriptor::index`]; use - * [`fetch`](BundleSource::fetch_bundle) when entry data is needed. + * @suppress */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `fetchDescriptor`(`bundleName`: kotlin.String) : BundleDescriptor { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_fetch_descriptor( - uniffiHandle, - FfiConverterString.lower(`bundleName`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_u64(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_u64(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_u64(future) }, - // lift function - { FfiConverterTypeBundleDescriptor.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) + companion object + +} + + +/** + * @suppress + */ +public object FfiConverterTypeCancellation: FfiConverter { + override fun lower(value: Cancellation): Long { + return value.uniffiCloneHandle() } - - /** - * Loads the full remote bundle for `bundle_name` at `version`, bypassing the - * builtin source and version resolution. - */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `fetchRemoteBundle`(`bundleName`: kotlin.String, `version`: kotlin.String) : Bundle { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_fetch_remote_bundle( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_u64(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_u64(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_u64(future) }, - // lift function - { FfiConverterTypeBundle.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) + override fun lift(value: Long): Cancellation { + return Cancellation(UniffiWithHandle, value) + } + + override fun read(buf: ByteBuffer): Cancellation { + return lift(buf.getLong()) + } + + override fun allocationSize(value: Cancellation) = 8UL + + override fun write(value: Cancellation, buf: ByteBuffer) { + buf.putLong(lower(value)) } +} + + +// This template implements a class for working with a Rust struct via a handle +// to the live Rust struct on the other side of the FFI. +// +// There's some subtlety here, because we have to be careful not to operate on a Rust +// struct after it has been dropped, and because we must expose a public API for freeing +// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: +// +// * Each instance holds an opaque handle to the underlying Rust struct. +// Method calls need to read this handle from the object's state and pass it in to +// the Rust FFI. +// +// * When an instance is no longer needed, its handle should be passed to a +// special destructor function provided by the Rust FFI, which will drop the +// underlying Rust struct. +// +// * Given an instance, calling code is expected to call the special +// `destroy` method in order to free it after use, either by calling it explicitly +// or by using a higher-level helper like the `use` method. Failing to do so risks +// leaking the underlying Rust struct. +// +// * We can't assume that calling code will do the right thing, and must be prepared +// to handle Kotlin method calls executing concurrently with or even after a call to +// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. +// +// * We must never allow Rust code to operate on the underlying Rust struct after +// the destructor has been called, and must never call the destructor more than once. +// Doing so may trigger memory unsafety. +// +// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` +// is implemented to call the destructor when the Kotlin object becomes unreachable. +// This is done in a background thread. This is not a panacea, and client code should be aware that +// 1. the thread may starve if some there are objects that have poorly performing +// `drop` methods or do significant work in their `drop` methods. +// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, +// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). +// +// If we try to implement this with mutual exclusion on access to the handle, there is the +// possibility of a race between a method call and a concurrent call to `destroy`: +// +// * Thread A starts a method call, reads the value of the handle, but is interrupted +// before it can pass the handle over the FFI to Rust. +// * Thread B calls `destroy` and frees the underlying Rust struct. +// * Thread A resumes, passing the already-read handle value to Rust and triggering +// a use-after-free. +// +// One possible solution would be to use a `ReadWriteLock`, with each method call taking +// a read lock (and thus allowed to run concurrently) and the special `destroy` method +// taking a write lock (and thus blocking on live method calls). However, we aim not to +// generate methods with any hidden blocking semantics, and a `destroy` method that might +// block if called incorrectly seems to meet that bar. +// +// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track +// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` +// has been called. These are updated according to the following rules: +// +// * The initial value of the counter is 1, indicating a live object with no in-flight calls. +// The initial value for the flag is false. +// +// * At the start of each method call, we atomically check the counter. +// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. +// If it is nonzero them we atomically increment it by 1 and proceed with the method call. +// +// * At the end of each method call, we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// * When `destroy` is called, we atomically flip the flag from false to true. +// If the flag was already true we silently fail. +// Otherwise we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, +// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. +// +// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been +// called *and* all in-flight method calls have completed, avoiding violating any of the expectations +// of the underlying Rust code. +// +// This makes a cleaner a better alternative to _not_ calling `destroy()` as +// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` +// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner +// thread may be starved, and the app will leak memory. +// +// In this case, `destroy`ing manually may be a better solution. +// +// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects +// with Rust peers are reclaimed: +// +// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: +// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: +// 3. The memory is reclaimed when the process terminates. +// +// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 +// + +/** + * Fixed-size bundle file header containing format metadata. + */ +public interface HeaderInterface { /** - * Resolves the on-disk path of the builtin bundle `bundle_name` at `version`, - * without checking whether the file exists. + * Byte offset at which the index section ends (and data section begins). */ - @Throws(WebviewBundleException::class)override fun `getBuiltinBundleFilepath`(`bundleName`: kotlin.String, `version`: kotlin.String): kotlin.String { - return FfiConverterString.lift( - callWithHandle { - uniffiRustCallWithError(WebviewBundleException) { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_get_builtin_bundle_filepath( - it, - FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`),_status) -} - } - ) - } + fun `indexEndOffset`(): kotlin.ULong - + /** + * Byte length of the serialized index section. + */ + fun `indexSize`(): kotlin.UInt /** - * Resolves the on-disk path of the remote bundle `bundle_name` at `version`, - * without checking whether the file exists. + * Bundle format version encoded in the header. */ - @Throws(WebviewBundleException::class)override fun `getRemoteBundleFilepath`(`bundleName`: kotlin.String, `version`: kotlin.String): kotlin.String { - return FfiConverterString.lift( - callWithHandle { - uniffiRustCallWithError(WebviewBundleException) { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_get_remote_bundle_filepath( - it, - FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`),_status) -} - } - ) - } + fun `version`(): Version + companion object +} - - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `listBundles`() : List { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_list_bundles( - uniffiHandle, - - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterSequenceTypeListBundleItem.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) - } +/** + * Fixed-size bundle file header containing format metadata. + */ +open class Header: Disposable, AutoCloseable, HeaderInterface +{ - + @Suppress("UNUSED_PARAMETER") /** - * Loads the manifest metadata for the builtin bundle `bundle_name` at `version`, - * or `None` if no such entry exists. + * @suppress */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `loadBuiltinMetadata`(`bundleName`: kotlin.String, `version`: kotlin.String) : BundleManifestMetadata? { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_load_builtin_metadata( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterOptionalTypeBundleManifestMetadata.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) + constructor(withHandle: UniffiWithHandle, handle: Long) { + this.handle = handle + this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(handle)) } - /** - * Loads (and caches) the descriptor for the current version of `bundle_name`. - * Concurrent calls for the same bundle share a single load (single-flight) and - * return the cached descriptor until the active version changes or - * [`unload_descriptor`](BundleSource::unload_descriptor) is called. + * @suppress + * + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `loadDescriptor`(`bundleName`: kotlin.String) : LoadedDescriptor { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_load_descriptor( - uniffiHandle, - FfiConverterString.lower(`bundleName`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_u64(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_u64(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_u64(future) }, - // lift function - { FfiConverterTypeLoadedDescriptor.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) + @Suppress("UNUSED_PARAMETER") + constructor(noHandle: NoHandle) { + this.handle = 0 + this.cleanable = null } - - /** - * Loads the manifest metadata for the remote bundle `bundle_name` at `version`, - * or `None` if no such entry exists. - */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `loadRemoteMetadata`(`bundleName`: kotlin.String, `version`: kotlin.String) : BundleManifestMetadata? { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_load_remote_metadata( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterOptionalTypeBundleManifestMetadata.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) + protected val handle: Long + protected val cleanable: UniffiCleaner.Cleanable? + + private val wasDestroyed = AtomicBoolean(false) + private val callCounter = AtomicLong(1) + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } } - - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `loadVersion`(`bundleName`: kotlin.String) : BundleSourceVersion? { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_load_version( - uniffiHandle, - FfiConverterString.lower(`bundleName`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterOptionalTypeBundleSourceVersion.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) + @Synchronized + override fun close() { + this.destroy() } - - /** - * Removes every staged remote version except the retained set (current and - * previous). Returns the versions that were removed. - */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `pruneRemoteBundles`(`bundleName`: kotlin.String) : List { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_prune_remote_bundles( - uniffiHandle, - FfiConverterString.lower(`bundleName`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterSequenceString.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) + internal inline fun callWithHandle(block: (handle: Long) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.get() + if (c == 0L) { + throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the handle being freed concurrently. + try { + return block(this.uniffiCloneHandle()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } } - - /** - * Returns the remote versions that pruning retains (the current and previous). - */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `remoteRetainedVersions`(`bundleName`: kotlin.String) : List { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_remote_retained_versions( - uniffiHandle, - FfiConverterString.lower(`bundleName`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterSequenceString.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiCleanAction(private val handle: Long) : Runnable { + override fun run() { + if (handle == 0.toLong()) { + // Fake object created with `NoHandle`, don't try to free. + return; + } + uniffiRustCall { status -> + UniffiLib.uniffi_wvb_ffi_fn_free_header(handle, status) + } + } } - /** - * Removes a single staged remote bundle version: drops its manifest entry and - * deletes its file from disk. Returns `true` if the entry existed. + * @suppress */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `removeRemoteBundle`(`bundleName`: kotlin.String, `version`: kotlin.String) : kotlin.Boolean { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_remove_remote_bundle( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_i8(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_i8(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_i8(future) }, - // lift function - { FfiConverterBoolean.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) + fun uniffiCloneHandle(): Long { + if (handle == 0.toLong()) { + throw InternalException("uniffiCloneHandle() called on NoHandle object"); + } + return uniffiRustCall() { status -> + UniffiLib.uniffi_wvb_ffi_fn_clone_header(handle, status) + } } - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `resolveFilepath`(`bundleName`: kotlin.String) : kotlin.String { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_resolve_filepath( - uniffiHandle, - FfiConverterString.lower(`bundleName`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterString.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, + /** + * Byte offset at which the index section ends (and data section begins). + */override fun `indexEndOffset`(): kotlin.ULong { + return FfiConverterULong.lift( + callWithHandle { + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_method_header_index_end_offset( + it, + _status) +} + } ) } + /** - * Drops the cached descriptor for `bundle_name`, if present. Already-returned - * [`LoadedDescriptor`] handles keep working; the next [`load_descriptor`] - * reloads from disk. Returns `true` if a cached descriptor was removed. - */override fun `unloadDescriptor`(`bundleName`: kotlin.String): kotlin.Boolean { - return FfiConverterBoolean.lift( + * Byte length of the serialized index section. + */override fun `indexSize`(): kotlin.UInt { + return FfiConverterUInt.lift( callWithHandle { uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_unload_descriptor( + UniffiLib.uniffi_wvb_ffi_fn_method_header_index_size( it, - FfiConverterString.lower(`bundleName`),_status) + _status) } } ) @@ -4044,48 +3968,20 @@ open class BundleSource: Disposable, AutoCloseable, BundleSourceInterface - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `updateVersion`(`bundleName`: kotlin.String, `version`: kotlin.String) { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_update_version( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_void(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_void(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_void(future) }, - // lift function - { Unit }, - - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) + /** + * Bundle format version encoded in the header. + */override fun `version`(): Version { + return FfiConverterTypeVersion.lift( + callWithHandle { + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_method_header_version( + it, + _status) +} } - - - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `writeRemoteBundle`(`bundleName`: kotlin.String, `version`: kotlin.String, `bundle`: Bundle, `metadata`: BundleManifestMetadata) { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_bundlesource_write_remote_bundle( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`),FfiConverterTypeBundle.lower(`bundle`),FfiConverterTypeBundleManifestMetadata.lower(`metadata`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_void(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_void(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_void(future) }, - // lift function - { Unit }, - - // Error FFI converter - WebviewBundleException.ErrorHandler, ) } + @@ -4105,22 +4001,22 @@ open class BundleSource: Disposable, AutoCloseable, BundleSourceInterface /** * @suppress */ -public object FfiConverterTypeBundleSource: FfiConverter { - override fun lower(value: BundleSource): Long { +public object FfiConverterTypeHeader: FfiConverter { + override fun lower(value: Header): Long { return value.uniffiCloneHandle() } - override fun lift(value: Long): BundleSource { - return BundleSource(UniffiWithHandle, value) + override fun lift(value: Long): Header { + return Header(UniffiWithHandle, value) } - override fun read(buf: ByteBuffer): BundleSource { + override fun read(buf: ByteBuffer): Header { return lift(buf.getLong()) } - override fun allocationSize(value: BundleSource) = 8UL + override fun allocationSize(value: Header) = 8UL - override fun write(value: BundleSource, buf: ByteBuffer) { + override fun write(value: Header, buf: ByteBuffer) { buf.putLong(lower(value)) } } @@ -4222,32 +4118,32 @@ public object FfiConverterTypeBundleSource: FfiConverter { /** - * Fixed-size bundle file header containing format metadata. + * View into the index section of a bundle. + * + * Holds the index metadata itself, so it is available on a metadata-only descriptor + * (from `BundleSource::fetch_descriptor`) as well as on a fully loaded [`Bundle`]. */ -public interface HeaderInterface { +public interface IndexInterface { - /** - * Byte offset at which the index section ends (and data section begins). - */ - fun `indexEndOffset`(): kotlin.ULong + fun `containsPath`(`path`: kotlin.String): kotlin.Boolean /** - * Byte length of the serialized index section. + * Returns all index entries keyed by their path (e.g. `"/index.html"`). */ - fun `indexSize`(): kotlin.UInt + fun `entries`(): Map - /** - * Bundle format version encoded in the header. - */ - fun `version`(): Version + fun `getEntry`(`path`: kotlin.String): IndexEntry? companion object } /** - * Fixed-size bundle file header containing format metadata. + * View into the index section of a bundle. + * + * Holds the index metadata itself, so it is available on a metadata-only descriptor + * (from `BundleSource::fetch_descriptor`) as well as on a fully loaded [`Bundle`]. */ -open class Header: Disposable, AutoCloseable, HeaderInterface +open class Index: Disposable, AutoCloseable, IndexInterface { @Suppress("UNUSED_PARAMETER") @@ -4326,7 +4222,7 @@ open class Header: Disposable, AutoCloseable, HeaderInterface return; } uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_header(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_free_index(handle, status) } } } @@ -4339,20 +4235,17 @@ open class Header: Disposable, AutoCloseable, HeaderInterface throw InternalException("uniffiCloneHandle() called on NoHandle object"); } return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_header(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_clone_index(handle, status) } } - - /** - * Byte offset at which the index section ends (and data section begins). - */override fun `indexEndOffset`(): kotlin.ULong { - return FfiConverterULong.lift( + override fun `containsPath`(`path`: kotlin.String): kotlin.Boolean { + return FfiConverterBoolean.lift( callWithHandle { uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_header_index_end_offset( + UniffiLib.uniffi_wvb_ffi_fn_method_index_contains_path( it, - _status) + FfiConverterString.lower(`path`),_status) } } ) @@ -4361,12 +4254,12 @@ open class Header: Disposable, AutoCloseable, HeaderInterface /** - * Byte length of the serialized index section. - */override fun `indexSize`(): kotlin.UInt { - return FfiConverterUInt.lift( + * Returns all index entries keyed by their path (e.g. `"/index.html"`). + */override fun `entries`(): Map { + return FfiConverterMapStringTypeIndexEntry.lift( callWithHandle { uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_header_index_size( + UniffiLib.uniffi_wvb_ffi_fn_method_index_entries( it, _status) } @@ -4375,16 +4268,13 @@ open class Header: Disposable, AutoCloseable, HeaderInterface } - - /** - * Bundle format version encoded in the header. - */override fun `version`(): Version { - return FfiConverterTypeVersion.lift( + override fun `getEntry`(`path`: kotlin.String): IndexEntry? { + return FfiConverterOptionalTypeIndexEntry.lift( callWithHandle { uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_header_version( + UniffiLib.uniffi_wvb_ffi_fn_method_index_get_entry( it, - _status) + FfiConverterString.lower(`path`),_status) } } ) @@ -4409,22 +4299,22 @@ open class Header: Disposable, AutoCloseable, HeaderInterface /** * @suppress */ -public object FfiConverterTypeHeader: FfiConverter { - override fun lower(value: Header): Long { +public object FfiConverterTypeIndex: FfiConverter { + override fun lower(value: Index): Long { return value.uniffiCloneHandle() } - override fun lift(value: Long): Header { - return Header(UniffiWithHandle, value) + override fun lift(value: Long): Index { + return Index(UniffiWithHandle, value) } - override fun read(buf: ByteBuffer): Header { + override fun read(buf: ByteBuffer): Index { return lift(buf.getLong()) } - override fun allocationSize(value: Header) = 8UL + override fun allocationSize(value: Index) = 8UL - override fun write(value: Header, buf: ByteBuffer) { + override fun write(value: Index, buf: ByteBuffer) { buf.putLong(lower(value)) } } @@ -4526,32 +4416,32 @@ public object FfiConverterTypeHeader: FfiConverter { /** - * View into the index section of a bundle. - * - * Holds the index metadata itself, so it is available on a metadata-only descriptor - * (from `BundleSource::fetch_descriptor`) as well as on a fully loaded [`Bundle`]. + * A digest over some bytes, serialized as `:` (e.g. `"sha256:n4bQ..."`). */ -public interface IndexInterface { +public interface IntegrityInterface { - fun `containsPath`(`path`: kotlin.String): kotlin.Boolean + /** + * Serializes to `:`. + */ + fun `serialize`(): kotlin.String /** - * Returns all index entries keyed by their path (e.g. `"/index.html"`). + * Whether `data` digests to this integrity. */ - fun `entries`(): Map + fun `validate`(`data`: kotlin.ByteArray): kotlin.Boolean - fun `getEntry`(`path`: kotlin.String): IndexEntry? + /** + * The raw digest bytes. + */ + fun `value`(): kotlin.ByteArray companion object } /** - * View into the index section of a bundle. - * - * Holds the index metadata itself, so it is available on a metadata-only descriptor - * (from `BundleSource::fetch_descriptor`) as well as on a fully loaded [`Bundle`]. + * A digest over some bytes, serialized as `:` (e.g. `"sha256:n4bQ..."`). */ -open class Index: Disposable, AutoCloseable, IndexInterface +open class Integrity: Disposable, AutoCloseable, IntegrityInterface { @Suppress("UNUSED_PARAMETER") @@ -4630,7 +4520,7 @@ open class Index: Disposable, AutoCloseable, IndexInterface return; } uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_index(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_free_integrity(handle, status) } } } @@ -4643,17 +4533,20 @@ open class Index: Disposable, AutoCloseable, IndexInterface throw InternalException("uniffiCloneHandle() called on NoHandle object"); } return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_index(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_clone_integrity(handle, status) } } - override fun `containsPath`(`path`: kotlin.String): kotlin.Boolean { - return FfiConverterBoolean.lift( + + /** + * Serializes to `:`. + */override fun `serialize`(): kotlin.String { + return FfiConverterString.lift( callWithHandle { uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_index_contains_path( + UniffiLib.uniffi_wvb_ffi_fn_method_integrity_serialize( it, - FfiConverterString.lower(`path`),_status) + _status) } } ) @@ -4662,27 +4555,30 @@ open class Index: Disposable, AutoCloseable, IndexInterface /** - * Returns all index entries keyed by their path (e.g. `"/index.html"`). - */override fun `entries`(): Map { - return FfiConverterMapStringTypeIndexEntry.lift( + * Whether `data` digests to this integrity. + */override fun `validate`(`data`: kotlin.ByteArray): kotlin.Boolean { + return FfiConverterBoolean.lift( callWithHandle { uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_index_entries( + UniffiLib.uniffi_wvb_ffi_fn_method_integrity_validate( it, - _status) + FfiConverterByteArray.lower(`data`),_status) } } ) } - override fun `getEntry`(`path`: kotlin.String): IndexEntry? { - return FfiConverterOptionalTypeIndexEntry.lift( + + /** + * The raw digest bytes. + */override fun `value`(): kotlin.ByteArray { + return FfiConverterByteArray.lift( callWithHandle { uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_index_get_entry( + UniffiLib.uniffi_wvb_ffi_fn_method_integrity_value( it, - FfiConverterString.lower(`path`),_status) + _status) } } ) @@ -4695,11 +4591,32 @@ open class Index: Disposable, AutoCloseable, IndexInterface + companion object { + fun `compute`(`algorithm`: IntegrityAlgorithm, `data`: kotlin.ByteArray): Integrity { + return FfiConverterTypeIntegrity.lift( + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_constructor_integrity_compute( - /** - * @suppress - */ - companion object + FfiConverterTypeIntegrityAlgorithm.lower(`algorithm`),FfiConverterByteArray.lower(`data`),_status) +} + ) + } + + + + @Throws(WebviewBundleException::class) fun `parse`(`integrity`: kotlin.String): Integrity { + return FfiConverterTypeIntegrity.lift( + uniffiRustCallWithError(WebviewBundleException) { _status -> + UniffiLib.uniffi_wvb_ffi_fn_constructor_integrity_parse( + + FfiConverterString.lower(`integrity`),_status) +} + ) + } + + + + } } @@ -4707,22 +4624,22 @@ open class Index: Disposable, AutoCloseable, IndexInterface /** * @suppress */ -public object FfiConverterTypeIndex: FfiConverter { - override fun lower(value: Index): Long { +public object FfiConverterTypeIntegrity: FfiConverter { + override fun lower(value: Integrity): Long { return value.uniffiCloneHandle() } - override fun lift(value: Long): Index { - return Index(UniffiWithHandle, value) + override fun lift(value: Long): Integrity { + return Integrity(UniffiWithHandle, value) } - override fun read(buf: ByteBuffer): Index { + override fun read(buf: ByteBuffer): Integrity { return lift(buf.getLong()) } - override fun allocationSize(value: Index) = 8UL + override fun allocationSize(value: Integrity) = 8UL - override fun write(value: Index, buf: ByteBuffer) { + override fun write(value: Integrity, buf: ByteBuffer) { buf.putLong(lower(value)) } } @@ -4824,32 +4741,54 @@ public object FfiConverterTypeIndex: FfiConverter { /** - * A digest over some bytes, serialized as `:` (e.g. `"sha256:n4bQ..."`). + * A descriptor loaded (and cached) by a [`Source`]. + * + * Holds the parsed header/index together with the filepath it was loaded from, so + * reading entry data always targets the exact bundle version that produced this + * descriptor — even if the source's active version is swapped concurrently. Entry + * data is read lazily from disk via [`LoadedDescriptor::get_data`], avoiding loading + * the whole bundle into memory. */ -public interface IntegrityInterface { +public interface LoadedDescriptorInterface { /** - * Serializes to `:`. + * Returns the bundle descriptor (header + index metadata). + * + * The returned descriptor carries no reference back to the source, so it can + * outlive this `LoadedDescriptor`. It holds only metadata, so its `index()` is + * unsupported; use [`get_data`](LoadedDescriptor::get_data) for entry data. */ - fun `serialize`(): kotlin.String + fun `descriptor`(): BundleDescriptor /** - * Whether `data` digests to this integrity. + * Reads the bytes for `path`, loading them lazily from disk. + * + * The read targets the bundle file this descriptor was loaded from, so the data + * stays consistent with [`descriptor`](LoadedDescriptor::descriptor) even if the + * source's active version changes meanwhile. Returns `None` if `path` does not + * exist in the bundle. */ - fun `validate`(`data`: kotlin.ByteArray): kotlin.Boolean + suspend fun `getData`(`path`: kotlin.String): kotlin.ByteArray? /** - * The raw digest bytes. + * Reads the xxHash-32 checksum for `path`, loading it lazily from disk. + * Returns `None` if `path` does not exist in the bundle. */ - fun `value`(): kotlin.ByteArray + suspend fun `getDataChecksum`(`path`: kotlin.String): kotlin.UInt? companion object } /** - * A digest over some bytes, serialized as `:` (e.g. `"sha256:n4bQ..."`). + * A descriptor loaded (and cached) by a [`Source`]. + * + * Holds the parsed header/index together with the filepath it was loaded from, so + * reading entry data always targets the exact bundle version that produced this + * descriptor — even if the source's active version is swapped concurrently. Entry + * data is read lazily from disk via [`LoadedDescriptor::get_data`], avoiding loading + * the whole bundle into memory. */ -open class Integrity: Disposable, AutoCloseable, IntegrityInterface +open class LoadedDescriptor: Disposable, AutoCloseable, LoadedDescriptorInterface { @Suppress("UNUSED_PARAMETER") @@ -4928,7 +4867,7 @@ open class Integrity: Disposable, AutoCloseable, IntegrityInterface return; } uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_integrity(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_free_loadeddescriptor(handle, status) } } } @@ -4941,18 +4880,22 @@ open class Integrity: Disposable, AutoCloseable, IntegrityInterface throw InternalException("uniffiCloneHandle() called on NoHandle object"); } return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_integrity(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_clone_loadeddescriptor(handle, status) } } /** - * Serializes to `:`. - */override fun `serialize`(): kotlin.String { - return FfiConverterString.lift( + * Returns the bundle descriptor (header + index metadata). + * + * The returned descriptor carries no reference back to the source, so it can + * outlive this `LoadedDescriptor`. It holds only metadata, so its `index()` is + * unsupported; use [`get_data`](LoadedDescriptor::get_data) for entry data. + */override fun `descriptor`(): BundleDescriptor { + return FfiConverterTypeBundleDescriptor.lift( callWithHandle { uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_integrity_serialize( + UniffiLib.uniffi_wvb_ffi_fn_method_loadeddescriptor_descriptor( it, _status) } @@ -4963,74 +4906,69 @@ open class Integrity: Disposable, AutoCloseable, IntegrityInterface /** - * Whether `data` digests to this integrity. - */override fun `validate`(`data`: kotlin.ByteArray): kotlin.Boolean { - return FfiConverterBoolean.lift( - callWithHandle { - uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_integrity_validate( - it, - FfiConverterByteArray.lower(`data`),_status) -} - } - ) - } - - - - /** - * The raw digest bytes. - */override fun `value`(): kotlin.ByteArray { - return FfiConverterByteArray.lift( - callWithHandle { - uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_integrity_value( - it, - _status) -} - } - ) - } - - - - - - - - - companion object { - - /** - * Computes the integrity of `data` with `algorithm`. - */ fun `compute`(`algorithm`: IntegrityAlgorithm, `data`: kotlin.ByteArray): Integrity { - return FfiConverterTypeIntegrity.lift( - uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_constructor_integrity_compute( - - FfiConverterTypeIntegrityAlgorithm.lower(`algorithm`),FfiConverterByteArray.lower(`data`),_status) -} + * Reads the bytes for `path`, loading them lazily from disk. + * + * The read targets the bundle file this descriptor was loaded from, so the data + * stays consistent with [`descriptor`](LoadedDescriptor::descriptor) even if the + * source's active version changes meanwhile. Returns `None` if `path` does not + * exist in the bundle. + */ + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `getData`(`path`: kotlin.String) : kotlin.ByteArray? { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_loadeddescriptor_get_data( + uniffiHandle, + FfiConverterString.lower(`path`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterOptionalByteArray.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, ) } - - + /** - * Parses a serialized integrity string (e.g. `"sha256:n4bQ..."`). + * Reads the xxHash-32 checksum for `path`, loading it lazily from disk. + * Returns `None` if `path` does not exist in the bundle. */ - @Throws(WebviewBundleException::class) fun `parse`(`integrity`: kotlin.String): Integrity { - return FfiConverterTypeIntegrity.lift( - uniffiRustCallWithError(WebviewBundleException) { _status -> - UniffiLib.uniffi_wvb_ffi_fn_constructor_integrity_parse( - - FfiConverterString.lower(`integrity`),_status) -} + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `getDataChecksum`(`path`: kotlin.String) : kotlin.UInt? { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_loadeddescriptor_get_data_checksum( + uniffiHandle, + FfiConverterString.lower(`path`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterOptionalUInt.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, ) } + - - } + + + + + + /** + * @suppress + */ + companion object } @@ -5038,22 +4976,22 @@ open class Integrity: Disposable, AutoCloseable, IntegrityInterface /** * @suppress */ -public object FfiConverterTypeIntegrity: FfiConverter { - override fun lower(value: Integrity): Long { +public object FfiConverterTypeLoadedDescriptor: FfiConverter { + override fun lower(value: LoadedDescriptor): Long { return value.uniffiCloneHandle() } - override fun lift(value: Long): Integrity { - return Integrity(UniffiWithHandle, value) + override fun lift(value: Long): LoadedDescriptor { + return LoadedDescriptor(UniffiWithHandle, value) } - override fun read(buf: ByteBuffer): Integrity { + override fun read(buf: ByteBuffer): LoadedDescriptor { return lift(buf.getLong()) } - override fun allocationSize(value: Integrity) = 8UL + override fun allocationSize(value: LoadedDescriptor) = 8UL - override fun write(value: Integrity, buf: ByteBuffer) { + override fun write(value: LoadedDescriptor, buf: ByteBuffer) { buf.putLong(lower(value)) } } @@ -5155,19 +5093,30 @@ public object FfiConverterTypeIntegrity: FfiConverter { /** - * A custom checker that validates a bundle's bytes against its integrity string. + * Proxies HTTP-like requests to another HTTP server (typically a local dev server). + * + * The target is resolved per request — either from a static host mapping + * (e.g. `{"myapp": "http://localhost:8080"}`, keyed by uri host) or by a custom + * [`ProxyResolver`]. A request whose target cannot be resolved fails with an error. */ -public interface IntegrityCheck { +public interface ProxyProtocolHandlerInterface { - suspend fun `check`(`data`: kotlin.ByteArray, `integrity`: kotlin.String): kotlin.Boolean + /** + * Forwards the request — including `body`, for POST/PUT/PATCH — to the resolved target. + */ + suspend fun `handle`(`method`: HttpMethod, `uri`: kotlin.String, `headers`: Map? = null, `body`: kotlin.ByteArray? = null): HttpResponse companion object } /** - * A custom checker that validates a bundle's bytes against its integrity string. + * Proxies HTTP-like requests to another HTTP server (typically a local dev server). + * + * The target is resolved per request — either from a static host mapping + * (e.g. `{"myapp": "http://localhost:8080"}`, keyed by uri host) or by a custom + * [`ProxyResolver`]. A request whose target cannot be resolved fails with an error. */ -open class IntegrityCheckImpl: Disposable, AutoCloseable, IntegrityCheck +open class ProxyProtocolHandler: Disposable, AutoCloseable, ProxyProtocolHandlerInterface { @Suppress("UNUSED_PARAMETER") @@ -5191,6 +5140,17 @@ open class IntegrityCheckImpl: Disposable, AutoCloseable, IntegrityCheck this.handle = 0 this.cleanable = null } + /** + * Proxy by a static host mapping, keyed by the uri host. + */ + constructor(`hosts`: Map) : + this(UniffiWithHandle, + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_constructor_proxyprotocolhandler_new( + + FfiConverterMapStringString.lower(`hosts`),_status) +} + ) protected val handle: Long protected val cleanable: UniffiCleaner.Cleanable? @@ -5246,7 +5206,7 @@ open class IntegrityCheckImpl: Disposable, AutoCloseable, IntegrityCheck return; } uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_integritycheck(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_free_proxyprotocolhandler(handle, status) } } } @@ -5259,27 +5219,31 @@ open class IntegrityCheckImpl: Disposable, AutoCloseable, IntegrityCheck throw InternalException("uniffiCloneHandle() called on NoHandle object"); } return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_integritycheck(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_clone_proxyprotocolhandler(handle, status) } } + /** + * Forwards the request — including `body`, for POST/PUT/PATCH — to the resolved target. + */ + @Throws(WebviewBundleException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `check`(`data`: kotlin.ByteArray, `integrity`: kotlin.String) : kotlin.Boolean { + override suspend fun `handle`(`method`: HttpMethod, `uri`: kotlin.String, `headers`: Map?, `body`: kotlin.ByteArray?) : HttpResponse { return uniffiRustCallAsync( callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_integritycheck_check( + UniffiLib.uniffi_wvb_ffi_fn_method_proxyprotocolhandler_handle( uniffiHandle, - FfiConverterByteArray.lower(`data`),FfiConverterString.lower(`integrity`), + FfiConverterTypeHttpMethod.lower(`method`),FfiConverterString.lower(`uri`),FfiConverterOptionalMapStringString.lower(`headers`),FfiConverterOptionalByteArray.lower(`body`), ) }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_i8(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_i8(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_i8(future) }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, // lift function - { FfiConverterBoolean.lift(it) }, + { FfiConverterTypeHttpResponse.lift(it) }, // Error FFI converter - UniffiNullRustCallStatusErrorHandler, + WebviewBundleException.ErrorHandler, ) } @@ -5289,112 +5253,46 @@ open class IntegrityCheckImpl: Disposable, AutoCloseable, IntegrityCheck - + companion object { + /** - * @suppress - */ - companion object + * Proxy by a custom resolver. + */ fun `custom`(`resolver`: ProxyResolver): ProxyProtocolHandler { + return FfiConverterTypeProxyProtocolHandler.lift( + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_constructor_proxyprotocolhandler_custom( + FfiConverterTypeProxyResolver.lower(`resolver`),_status) } - - - -// Put the implementation in an object so we don't pollute the top-level namespace -internal object uniffiCallbackInterfaceIntegrityCheck { - internal object `check`: UniffiCallbackInterfaceIntegrityCheckMethod0 { - override fun callback(`uniffiHandle`: Long,`data`: RustBuffer.ByValue,`integrity`: RustBuffer.ByValue,`uniffiFutureCallback`: UniffiForeignFutureCompleteI8,`uniffiCallbackData`: Long,`uniffiOutDroppedCallback`: UniffiForeignFutureDroppedCallbackStruct,) { - val uniffiObj = FfiConverterTypeIntegrityCheck.handleMap.get(uniffiHandle) - val makeCall = suspend { -> - uniffiObj.`check`( - FfiConverterByteArray.lift(`data`), - FfiConverterString.lift(`integrity`), - ) - } - val uniffiHandleSuccess = { returnValue: kotlin.Boolean -> - val uniffiResult = UniffiForeignFutureResultI8.UniffiByValue( - FfiConverterBoolean.lower(returnValue), - UniffiRustCallStatus.ByValue() - ) - uniffiResult.write() - uniffiFutureCallback.callback(uniffiCallbackData, uniffiResult) - } - val uniffiHandleError = { callStatus: UniffiRustCallStatus.ByValue -> - uniffiFutureCallback.callback( - uniffiCallbackData, - UniffiForeignFutureResultI8.UniffiByValue( - 0.toByte(), - callStatus, - ), - ) - } - uniffiTraitInterfaceCallAsync( - makeCall, - uniffiHandleSuccess, - uniffiHandleError, - uniffiOutDroppedCallback - ) - } - } - - internal object uniffiFree: UniffiCallbackInterfaceFree { - override fun callback(handle: Long) { - FfiConverterTypeIntegrityCheck.handleMap.remove(handle) - } - } - - internal object uniffiClone: UniffiCallbackInterfaceClone { - override fun callback(handle: Long): Long { - return FfiConverterTypeIntegrityCheck.handleMap.clone(handle) - } - } - - internal var vtable = UniffiVTableCallbackInterfaceIntegrityCheck.UniffiByValue( - uniffiFree, - uniffiClone, - `check`, ) + } + - // Registers the foreign callback with the Rust side. - // This method is generated for each callback interface. - internal fun register(lib: UniffiLib) { - lib.uniffi_wvb_ffi_fn_init_callback_vtable_integritycheck(vtable) + } + } + /** * @suppress */ -public object FfiConverterTypeIntegrityCheck: FfiConverter { - internal val handleMap = UniffiHandleMap() - - override fun lower(value: IntegrityCheck): Long { - if (value is IntegrityCheckImpl) { - // Rust-implemented object. Clone the handle and return it - return value.uniffiCloneHandle() - } else { - // Kotlin object, generate a new vtable handle and return that. - return handleMap.insert(value) - } +public object FfiConverterTypeProxyProtocolHandler: FfiConverter { + override fun lower(value: ProxyProtocolHandler): Long { + return value.uniffiCloneHandle() } - override fun lift(value: Long): IntegrityCheck { - if ((value and 1.toLong()) == 0.toLong()) { - // Rust-generated handle, construct a new class that uses the handle to implement the - // interface - return IntegrityCheckImpl(UniffiWithHandle, value) - } else { - // Kotlin-generated handle, get the object from the handle map - return handleMap.remove(value) - } + override fun lift(value: Long): ProxyProtocolHandler { + return ProxyProtocolHandler(UniffiWithHandle, value) } - override fun read(buf: ByteBuffer): IntegrityCheck { + override fun read(buf: ByteBuffer): ProxyProtocolHandler { return lift(buf.getLong()) } - override fun allocationSize(value: IntegrityCheck) = 8UL + override fun allocationSize(value: ProxyProtocolHandler) = 8UL - override fun write(value: IntegrityCheck, buf: ByteBuffer) { + override fun write(value: ProxyProtocolHandler, buf: ByteBuffer) { buf.putLong(lower(value)) } } @@ -5496,54 +5394,25 @@ public object FfiConverterTypeIntegrityCheck: FfiConverter /** - * A descriptor loaded (and cached) by a [`BundleSource`]. + * Resolves the proxy target for a request uri, e.g. `http://localhost:3000`. * - * Holds the parsed header/index together with the filepath it was loaded from, so - * reading entry data always targets the exact bundle version that produced this - * descriptor — even if the source's active version is swapped concurrently. Entry - * data is read lazily from disk via [`LoadedDescriptor::get_data`], avoiding loading - * the whole bundle into memory. + * The path and query of the request are appended to the returned target. Return `null` to + * not proxy the request; the handler then fails with `CannotResolveProxyServer`. */ -public interface LoadedDescriptorInterface { - - /** - * Returns the bundle descriptor (header + index metadata). - * - * The returned descriptor carries no reference back to the source, so it can - * outlive this `LoadedDescriptor`. It holds only metadata, so its `index()` is - * unsupported; use [`get_data`](LoadedDescriptor::get_data) for entry data. - */ - fun `descriptor`(): BundleDescriptor +public interface ProxyResolver { - /** - * Reads the bytes for `path`, loading them lazily from disk. - * - * The read targets the bundle file this descriptor was loaded from, so the data - * stays consistent with [`descriptor`](LoadedDescriptor::descriptor) even if the - * source's active version changes meanwhile. Returns `None` if `path` does not - * exist in the bundle. - */ - suspend fun `getData`(`path`: kotlin.String): kotlin.ByteArray? - - /** - * Reads the xxHash-32 checksum for `path`, loading it lazily from disk. - * Returns `None` if `path` does not exist in the bundle. - */ - suspend fun `getDataChecksum`(`path`: kotlin.String): kotlin.UInt? + suspend fun `resolve`(`uri`: kotlin.String): kotlin.String? companion object } /** - * A descriptor loaded (and cached) by a [`BundleSource`]. + * Resolves the proxy target for a request uri, e.g. `http://localhost:3000`. * - * Holds the parsed header/index together with the filepath it was loaded from, so - * reading entry data always targets the exact bundle version that produced this - * descriptor — even if the source's active version is swapped concurrently. Entry - * data is read lazily from disk via [`LoadedDescriptor::get_data`], avoiding loading - * the whole bundle into memory. + * The path and query of the request are appended to the returned target. Return `null` to + * not proxy the request; the handler then fails with `CannotResolveProxyServer`. */ -open class LoadedDescriptor: Disposable, AutoCloseable, LoadedDescriptorInterface +open class ProxyResolverImpl: Disposable, AutoCloseable, ProxyResolver { @Suppress("UNUSED_PARAMETER") @@ -5568,91 +5437,1957 @@ open class LoadedDescriptor: Disposable, AutoCloseable, LoadedDescriptorInterfac this.cleanable = null } - protected val handle: Long - protected val cleanable: UniffiCleaner.Cleanable? - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - override fun destroy() { - // Only allow a single call to this method. - // TODO: maybe we should log a warning if called more than once? - if (this.wasDestroyed.compareAndSet(false, true)) { - // This decrement always matches the initial count of 1 given at creation time. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } + protected val handle: Long + protected val cleanable: UniffiCleaner.Cleanable? + + private val wasDestroyed = AtomicBoolean(false) + private val callCounter = AtomicLong(1) + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } + } + + @Synchronized + override fun close() { + this.destroy() + } + + internal inline fun callWithHandle(block: (handle: Long) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.get() + if (c == 0L) { + throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the handle being freed concurrently. + try { + return block(this.uniffiCloneHandle()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiCleanAction(private val handle: Long) : Runnable { + override fun run() { + if (handle == 0.toLong()) { + // Fake object created with `NoHandle`, don't try to free. + return; + } + uniffiRustCall { status -> + UniffiLib.uniffi_wvb_ffi_fn_free_proxyresolver(handle, status) + } + } + } + + /** + * @suppress + */ + fun uniffiCloneHandle(): Long { + if (handle == 0.toLong()) { + throw InternalException("uniffiCloneHandle() called on NoHandle object"); + } + return uniffiRustCall() { status -> + UniffiLib.uniffi_wvb_ffi_fn_clone_proxyresolver(handle, status) + } + } + + + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `resolve`(`uri`: kotlin.String) : kotlin.String? { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_proxyresolver_resolve( + uniffiHandle, + FfiConverterString.lower(`uri`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterOptionalString.lift(it) }, + // Error FFI converter + UniffiNullRustCallStatusErrorHandler, + ) + } + + + + + + + + + /** + * @suppress + */ + companion object + +} + + + +// Put the implementation in an object so we don't pollute the top-level namespace +internal object uniffiCallbackInterfaceProxyResolver { + internal object `resolve`: UniffiCallbackInterfaceProxyResolverMethod0 { + override fun callback(`uniffiHandle`: Long,`uri`: RustBuffer.ByValue,`uniffiFutureCallback`: UniffiForeignFutureCompleteRustBuffer,`uniffiCallbackData`: Long,`uniffiOutDroppedCallback`: UniffiForeignFutureDroppedCallbackStruct,) { + val uniffiObj = FfiConverterTypeProxyResolver.handleMap.get(uniffiHandle) + val makeCall = suspend { -> + uniffiObj.`resolve`( + FfiConverterString.lift(`uri`), + ) + } + val uniffiHandleSuccess = { returnValue: kotlin.String? -> + val uniffiResult = UniffiForeignFutureResultRustBuffer.UniffiByValue( + FfiConverterOptionalString.lower(returnValue), + UniffiRustCallStatus.ByValue() + ) + uniffiResult.write() + uniffiFutureCallback.callback(uniffiCallbackData, uniffiResult) + } + val uniffiHandleError = { callStatus: UniffiRustCallStatus.ByValue -> + uniffiFutureCallback.callback( + uniffiCallbackData, + UniffiForeignFutureResultRustBuffer.UniffiByValue( + RustBuffer.ByValue(), + callStatus, + ), + ) + } + uniffiTraitInterfaceCallAsync( + makeCall, + uniffiHandleSuccess, + uniffiHandleError, + uniffiOutDroppedCallback + ) + } + } + + internal object uniffiFree: UniffiCallbackInterfaceFree { + override fun callback(handle: Long) { + FfiConverterTypeProxyResolver.handleMap.remove(handle) + } + } + + internal object uniffiClone: UniffiCallbackInterfaceClone { + override fun callback(handle: Long): Long { + return FfiConverterTypeProxyResolver.handleMap.clone(handle) + } + } + + internal var vtable = UniffiVTableCallbackInterfaceProxyResolver.UniffiByValue( + uniffiFree, + uniffiClone, + `resolve`, + ) + + // Registers the foreign callback with the Rust side. + // This method is generated for each callback interface. + internal fun register(lib: UniffiLib) { + lib.uniffi_wvb_ffi_fn_init_callback_vtable_proxyresolver(vtable) + } +} + +/** + * @suppress + */ +public object FfiConverterTypeProxyResolver: FfiConverter { + internal val handleMap = UniffiHandleMap() + + override fun lower(value: ProxyResolver): Long { + if (value is ProxyResolverImpl) { + // Rust-implemented object. Clone the handle and return it + return value.uniffiCloneHandle() + } else { + // Kotlin object, generate a new vtable handle and return that. + return handleMap.insert(value) + } + } + + override fun lift(value: Long): ProxyResolver { + if ((value and 1.toLong()) == 0.toLong()) { + // Rust-generated handle, construct a new class that uses the handle to implement the + // interface + return ProxyResolverImpl(UniffiWithHandle, value) + } else { + // Kotlin-generated handle, get the object from the handle map + return handleMap.remove(value) + } + } + + override fun read(buf: ByteBuffer): ProxyResolver { + return lift(buf.getLong()) + } + + override fun allocationSize(value: ProxyResolver) = 8UL + + override fun write(value: ProxyResolver, buf: ByteBuffer) { + buf.putLong(lower(value)) + } +} + + +// This template implements a class for working with a Rust struct via a handle +// to the live Rust struct on the other side of the FFI. +// +// There's some subtlety here, because we have to be careful not to operate on a Rust +// struct after it has been dropped, and because we must expose a public API for freeing +// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: +// +// * Each instance holds an opaque handle to the underlying Rust struct. +// Method calls need to read this handle from the object's state and pass it in to +// the Rust FFI. +// +// * When an instance is no longer needed, its handle should be passed to a +// special destructor function provided by the Rust FFI, which will drop the +// underlying Rust struct. +// +// * Given an instance, calling code is expected to call the special +// `destroy` method in order to free it after use, either by calling it explicitly +// or by using a higher-level helper like the `use` method. Failing to do so risks +// leaking the underlying Rust struct. +// +// * We can't assume that calling code will do the right thing, and must be prepared +// to handle Kotlin method calls executing concurrently with or even after a call to +// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. +// +// * We must never allow Rust code to operate on the underlying Rust struct after +// the destructor has been called, and must never call the destructor more than once. +// Doing so may trigger memory unsafety. +// +// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` +// is implemented to call the destructor when the Kotlin object becomes unreachable. +// This is done in a background thread. This is not a panacea, and client code should be aware that +// 1. the thread may starve if some there are objects that have poorly performing +// `drop` methods or do significant work in their `drop` methods. +// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, +// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). +// +// If we try to implement this with mutual exclusion on access to the handle, there is the +// possibility of a race between a method call and a concurrent call to `destroy`: +// +// * Thread A starts a method call, reads the value of the handle, but is interrupted +// before it can pass the handle over the FFI to Rust. +// * Thread B calls `destroy` and frees the underlying Rust struct. +// * Thread A resumes, passing the already-read handle value to Rust and triggering +// a use-after-free. +// +// One possible solution would be to use a `ReadWriteLock`, with each method call taking +// a read lock (and thus allowed to run concurrently) and the special `destroy` method +// taking a write lock (and thus blocking on live method calls). However, we aim not to +// generate methods with any hidden blocking semantics, and a `destroy` method that might +// block if called incorrectly seems to meet that bar. +// +// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track +// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` +// has been called. These are updated according to the following rules: +// +// * The initial value of the counter is 1, indicating a live object with no in-flight calls. +// The initial value for the flag is false. +// +// * At the start of each method call, we atomically check the counter. +// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. +// If it is nonzero them we atomically increment it by 1 and proceed with the method call. +// +// * At the end of each method call, we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// * When `destroy` is called, we atomically flip the flag from false to true. +// If the flag was already true we silently fail. +// Otherwise we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, +// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. +// +// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been +// called *and* all in-flight method calls have completed, avoiding violating any of the expectations +// of the underlying Rust code. +// +// This makes a cleaner a better alternative to _not_ calling `destroy()` as +// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` +// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner +// thread may be starved, and the app will leak memory. +// +// In this case, `destroy`ing manually may be a better solution. +// +// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects +// with Rust peers are reclaimed: +// +// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: +// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: +// 3. The memory is reclaimed when the process terminates. +// +// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 +// + + +/** + * HTTP client for a WebViewBundle remote server. + */ +public interface RemoteInterface { + + /** + * Downloads `url` into `filepath`. + * + * The optional cancellation token stops the transfer without deleting a previously completed + * bundle at the destination. + */ + suspend fun `download`(`url`: kotlin.String, `filepath`: kotlin.String, `cancellation`: Cancellation? = null) + + /** + * Gets the current update document, or `None` when its ETag has not changed. + */ + suspend fun `getUpdate`(`options`: RemoteGetUpdateOptions?): RemoteUpdateResponse? + + companion object +} + +/** + * HTTP client for a WebViewBundle remote server. + */ +open class Remote: Disposable, AutoCloseable, RemoteInterface +{ + + @Suppress("UNUSED_PARAMETER") + /** + * @suppress + */ + constructor(withHandle: UniffiWithHandle, handle: Long) { + this.handle = handle + this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(handle)) + } + + /** + * @suppress + * + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + @Suppress("UNUSED_PARAMETER") + constructor(noHandle: NoHandle) { + this.handle = 0 + this.cleanable = null + } + /** + * Creates a client for the server at `base_url` (e.g. `"https://bundles.example.com"`). + */ + constructor(`baseUrl`: kotlin.String, `options`: RemoteOptions? = null) : + this(UniffiWithHandle, + uniffiRustCallWithError(WebviewBundleException) { _status -> + UniffiLib.uniffi_wvb_ffi_fn_constructor_remote_new( + + FfiConverterString.lower(`baseUrl`),FfiConverterOptionalTypeRemoteOptions.lower(`options`),_status) +} + ) + + protected val handle: Long + protected val cleanable: UniffiCleaner.Cleanable? + + private val wasDestroyed = AtomicBoolean(false) + private val callCounter = AtomicLong(1) + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } + } + + @Synchronized + override fun close() { + this.destroy() + } + + internal inline fun callWithHandle(block: (handle: Long) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.get() + if (c == 0L) { + throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the handle being freed concurrently. + try { + return block(this.uniffiCloneHandle()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiCleanAction(private val handle: Long) : Runnable { + override fun run() { + if (handle == 0.toLong()) { + // Fake object created with `NoHandle`, don't try to free. + return; + } + uniffiRustCall { status -> + UniffiLib.uniffi_wvb_ffi_fn_free_remote(handle, status) + } + } + } + + /** + * @suppress + */ + fun uniffiCloneHandle(): Long { + if (handle == 0.toLong()) { + throw InternalException("uniffiCloneHandle() called on NoHandle object"); + } + return uniffiRustCall() { status -> + UniffiLib.uniffi_wvb_ffi_fn_clone_remote(handle, status) + } + } + + + /** + * Downloads `url` into `filepath`. + * + * The optional cancellation token stops the transfer without deleting a previously completed + * bundle at the destination. + */ + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `download`(`url`: kotlin.String, `filepath`: kotlin.String, `cancellation`: Cancellation?) { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_remote_download( + uniffiHandle, + FfiConverterString.lower(`url`),FfiConverterString.lower(`filepath`),FfiConverterOptionalTypeCancellation.lower(`cancellation`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_void(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_void(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_void(future) }, + // lift function + { Unit }, + + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + /** + * Gets the current update document, or `None` when its ETag has not changed. + */ + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `getUpdate`(`options`: RemoteGetUpdateOptions?) : RemoteUpdateResponse? { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_remote_get_update( + uniffiHandle, + FfiConverterOptionalTypeRemoteGetUpdateOptions.lower(`options`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterOptionalTypeRemoteUpdateResponse.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + + + + + + + /** + * @suppress + */ + companion object + +} + + +/** + * @suppress + */ +public object FfiConverterTypeRemote: FfiConverter { + override fun lower(value: Remote): Long { + return value.uniffiCloneHandle() + } + + override fun lift(value: Long): Remote { + return Remote(UniffiWithHandle, value) + } + + override fun read(buf: ByteBuffer): Remote { + return lift(buf.getLong()) + } + + override fun allocationSize(value: Remote) = 8UL + + override fun write(value: Remote, buf: ByteBuffer) { + buf.putLong(lower(value)) + } +} + + +// This template implements a class for working with a Rust struct via a handle +// to the live Rust struct on the other side of the FFI. +// +// There's some subtlety here, because we have to be careful not to operate on a Rust +// struct after it has been dropped, and because we must expose a public API for freeing +// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: +// +// * Each instance holds an opaque handle to the underlying Rust struct. +// Method calls need to read this handle from the object's state and pass it in to +// the Rust FFI. +// +// * When an instance is no longer needed, its handle should be passed to a +// special destructor function provided by the Rust FFI, which will drop the +// underlying Rust struct. +// +// * Given an instance, calling code is expected to call the special +// `destroy` method in order to free it after use, either by calling it explicitly +// or by using a higher-level helper like the `use` method. Failing to do so risks +// leaking the underlying Rust struct. +// +// * We can't assume that calling code will do the right thing, and must be prepared +// to handle Kotlin method calls executing concurrently with or even after a call to +// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. +// +// * We must never allow Rust code to operate on the underlying Rust struct after +// the destructor has been called, and must never call the destructor more than once. +// Doing so may trigger memory unsafety. +// +// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` +// is implemented to call the destructor when the Kotlin object becomes unreachable. +// This is done in a background thread. This is not a panacea, and client code should be aware that +// 1. the thread may starve if some there are objects that have poorly performing +// `drop` methods or do significant work in their `drop` methods. +// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, +// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). +// +// If we try to implement this with mutual exclusion on access to the handle, there is the +// possibility of a race between a method call and a concurrent call to `destroy`: +// +// * Thread A starts a method call, reads the value of the handle, but is interrupted +// before it can pass the handle over the FFI to Rust. +// * Thread B calls `destroy` and frees the underlying Rust struct. +// * Thread A resumes, passing the already-read handle value to Rust and triggering +// a use-after-free. +// +// One possible solution would be to use a `ReadWriteLock`, with each method call taking +// a read lock (and thus allowed to run concurrently) and the special `destroy` method +// taking a write lock (and thus blocking on live method calls). However, we aim not to +// generate methods with any hidden blocking semantics, and a `destroy` method that might +// block if called incorrectly seems to meet that bar. +// +// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track +// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` +// has been called. These are updated according to the following rules: +// +// * The initial value of the counter is 1, indicating a live object with no in-flight calls. +// The initial value for the flag is false. +// +// * At the start of each method call, we atomically check the counter. +// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. +// If it is nonzero them we atomically increment it by 1 and proceed with the method call. +// +// * At the end of each method call, we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// * When `destroy` is called, we atomically flip the flag from false to true. +// If the flag was already true we silently fail. +// Otherwise we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, +// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. +// +// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been +// called *and* all in-flight method calls have completed, avoiding violating any of the expectations +// of the underlying Rust code. +// +// This makes a cleaner a better alternative to _not_ calling `destroy()` as +// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` +// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner +// thread may be starved, and the app will leak memory. +// +// In this case, `destroy`ing manually may be a better solution. +// +// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects +// with Rust peers are reclaimed: +// +// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: +// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: +// 3. The memory is reclaimed when the process terminates. +// +// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 +// + + +/** + * A callback invoked with download progress as a bundle downloads. + */ +public interface RemoteOnDownload { + + /** + * Receives the current progress for a bundle download. + */ + fun `onDownload`(`data`: RemoteOnDownloadData) + + companion object +} + +/** + * A callback invoked with download progress as a bundle downloads. + */ +open class RemoteOnDownloadImpl: Disposable, AutoCloseable, RemoteOnDownload +{ + + @Suppress("UNUSED_PARAMETER") + /** + * @suppress + */ + constructor(withHandle: UniffiWithHandle, handle: Long) { + this.handle = handle + this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(handle)) + } + + /** + * @suppress + * + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + @Suppress("UNUSED_PARAMETER") + constructor(noHandle: NoHandle) { + this.handle = 0 + this.cleanable = null + } + + protected val handle: Long + protected val cleanable: UniffiCleaner.Cleanable? + + private val wasDestroyed = AtomicBoolean(false) + private val callCounter = AtomicLong(1) + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } + } + + @Synchronized + override fun close() { + this.destroy() + } + + internal inline fun callWithHandle(block: (handle: Long) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.get() + if (c == 0L) { + throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the handle being freed concurrently. + try { + return block(this.uniffiCloneHandle()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiCleanAction(private val handle: Long) : Runnable { + override fun run() { + if (handle == 0.toLong()) { + // Fake object created with `NoHandle`, don't try to free. + return; + } + uniffiRustCall { status -> + UniffiLib.uniffi_wvb_ffi_fn_free_remoteondownload(handle, status) + } + } + } + + /** + * @suppress + */ + fun uniffiCloneHandle(): Long { + if (handle == 0.toLong()) { + throw InternalException("uniffiCloneHandle() called on NoHandle object"); + } + return uniffiRustCall() { status -> + UniffiLib.uniffi_wvb_ffi_fn_clone_remoteondownload(handle, status) + } + } + + + /** + * Receives the current progress for a bundle download. + */override fun `onDownload`(`data`: RemoteOnDownloadData) + = + callWithHandle { + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_method_remoteondownload_on_download( + it, + FfiConverterTypeRemoteOnDownloadData.lower(`data`),_status) +} + } + + + + + + + + + + + /** + * @suppress + */ + companion object + +} + + + +// Put the implementation in an object so we don't pollute the top-level namespace +internal object uniffiCallbackInterfaceRemoteOnDownload { + internal object `onDownload`: UniffiCallbackInterfaceRemoteOnDownloadMethod0 { + override fun callback(`uniffiHandle`: Long,`data`: RustBuffer.ByValue,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) { + val uniffiObj = FfiConverterTypeRemoteOnDownload.handleMap.get(uniffiHandle) + val makeCall = { -> + uniffiObj.`onDownload`( + FfiConverterTypeRemoteOnDownloadData.lift(`data`), + ) + } + val writeReturn = { _: Unit -> Unit } + uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn) + } + } + + internal object uniffiFree: UniffiCallbackInterfaceFree { + override fun callback(handle: Long) { + FfiConverterTypeRemoteOnDownload.handleMap.remove(handle) + } + } + + internal object uniffiClone: UniffiCallbackInterfaceClone { + override fun callback(handle: Long): Long { + return FfiConverterTypeRemoteOnDownload.handleMap.clone(handle) + } + } + + internal var vtable = UniffiVTableCallbackInterfaceRemoteOnDownload.UniffiByValue( + uniffiFree, + uniffiClone, + `onDownload`, + ) + + // Registers the foreign callback with the Rust side. + // This method is generated for each callback interface. + internal fun register(lib: UniffiLib) { + lib.uniffi_wvb_ffi_fn_init_callback_vtable_remoteondownload(vtable) + } +} + +/** + * @suppress + */ +public object FfiConverterTypeRemoteOnDownload: FfiConverter { + internal val handleMap = UniffiHandleMap() + + override fun lower(value: RemoteOnDownload): Long { + if (value is RemoteOnDownloadImpl) { + // Rust-implemented object. Clone the handle and return it + return value.uniffiCloneHandle() + } else { + // Kotlin object, generate a new vtable handle and return that. + return handleMap.insert(value) + } + } + + override fun lift(value: Long): RemoteOnDownload { + if ((value and 1.toLong()) == 0.toLong()) { + // Rust-generated handle, construct a new class that uses the handle to implement the + // interface + return RemoteOnDownloadImpl(UniffiWithHandle, value) + } else { + // Kotlin-generated handle, get the object from the handle map + return handleMap.remove(value) + } + } + + override fun read(buf: ByteBuffer): RemoteOnDownload { + return lift(buf.getLong()) + } + + override fun allocationSize(value: RemoteOnDownload) = 8UL + + override fun write(value: RemoteOnDownload, buf: ByteBuffer) { + buf.putLong(lower(value)) + } +} + + +// This template implements a class for working with a Rust struct via a handle +// to the live Rust struct on the other side of the FFI. +// +// There's some subtlety here, because we have to be careful not to operate on a Rust +// struct after it has been dropped, and because we must expose a public API for freeing +// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: +// +// * Each instance holds an opaque handle to the underlying Rust struct. +// Method calls need to read this handle from the object's state and pass it in to +// the Rust FFI. +// +// * When an instance is no longer needed, its handle should be passed to a +// special destructor function provided by the Rust FFI, which will drop the +// underlying Rust struct. +// +// * Given an instance, calling code is expected to call the special +// `destroy` method in order to free it after use, either by calling it explicitly +// or by using a higher-level helper like the `use` method. Failing to do so risks +// leaking the underlying Rust struct. +// +// * We can't assume that calling code will do the right thing, and must be prepared +// to handle Kotlin method calls executing concurrently with or even after a call to +// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. +// +// * We must never allow Rust code to operate on the underlying Rust struct after +// the destructor has been called, and must never call the destructor more than once. +// Doing so may trigger memory unsafety. +// +// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` +// is implemented to call the destructor when the Kotlin object becomes unreachable. +// This is done in a background thread. This is not a panacea, and client code should be aware that +// 1. the thread may starve if some there are objects that have poorly performing +// `drop` methods or do significant work in their `drop` methods. +// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, +// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). +// +// If we try to implement this with mutual exclusion on access to the handle, there is the +// possibility of a race between a method call and a concurrent call to `destroy`: +// +// * Thread A starts a method call, reads the value of the handle, but is interrupted +// before it can pass the handle over the FFI to Rust. +// * Thread B calls `destroy` and frees the underlying Rust struct. +// * Thread A resumes, passing the already-read handle value to Rust and triggering +// a use-after-free. +// +// One possible solution would be to use a `ReadWriteLock`, with each method call taking +// a read lock (and thus allowed to run concurrently) and the special `destroy` method +// taking a write lock (and thus blocking on live method calls). However, we aim not to +// generate methods with any hidden blocking semantics, and a `destroy` method that might +// block if called incorrectly seems to meet that bar. +// +// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track +// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` +// has been called. These are updated according to the following rules: +// +// * The initial value of the counter is 1, indicating a live object with no in-flight calls. +// The initial value for the flag is false. +// +// * At the start of each method call, we atomically check the counter. +// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. +// If it is nonzero them we atomically increment it by 1 and proceed with the method call. +// +// * At the end of each method call, we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// * When `destroy` is called, we atomically flip the flag from false to true. +// If the flag was already true we silently fail. +// Otherwise we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, +// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. +// +// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been +// called *and* all in-flight method calls have completed, avoiding violating any of the expectations +// of the underlying Rust code. +// +// This makes a cleaner a better alternative to _not_ calling `destroy()` as +// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` +// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner +// thread may be starved, and the app will leak memory. +// +// In this case, `destroy`ing manually may be a better solution. +// +// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects +// with Rust peers are reclaimed: +// +// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: +// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: +// 3. The memory is reclaimed when the process terminates. +// +// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 +// + + +public interface SignatureCustomVerify { + + suspend fun `verify`(`message`: kotlin.ByteArray, `signature`: kotlin.String): kotlin.Boolean + + companion object +} + +open class SignatureCustomVerifyImpl: Disposable, AutoCloseable, SignatureCustomVerify +{ + + @Suppress("UNUSED_PARAMETER") + /** + * @suppress + */ + constructor(withHandle: UniffiWithHandle, handle: Long) { + this.handle = handle + this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(handle)) + } + + /** + * @suppress + * + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + @Suppress("UNUSED_PARAMETER") + constructor(noHandle: NoHandle) { + this.handle = 0 + this.cleanable = null + } + + protected val handle: Long + protected val cleanable: UniffiCleaner.Cleanable? + + private val wasDestroyed = AtomicBoolean(false) + private val callCounter = AtomicLong(1) + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } + } + + @Synchronized + override fun close() { + this.destroy() + } + + internal inline fun callWithHandle(block: (handle: Long) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.get() + if (c == 0L) { + throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the handle being freed concurrently. + try { + return block(this.uniffiCloneHandle()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiCleanAction(private val handle: Long) : Runnable { + override fun run() { + if (handle == 0.toLong()) { + // Fake object created with `NoHandle`, don't try to free. + return; + } + uniffiRustCall { status -> + UniffiLib.uniffi_wvb_ffi_fn_free_signaturecustomverify(handle, status) + } + } + } + + /** + * @suppress + */ + fun uniffiCloneHandle(): Long { + if (handle == 0.toLong()) { + throw InternalException("uniffiCloneHandle() called on NoHandle object"); + } + return uniffiRustCall() { status -> + UniffiLib.uniffi_wvb_ffi_fn_clone_signaturecustomverify(handle, status) + } + } + + + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `verify`(`message`: kotlin.ByteArray, `signature`: kotlin.String) : kotlin.Boolean { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_signaturecustomverify_verify( + uniffiHandle, + FfiConverterByteArray.lower(`message`),FfiConverterString.lower(`signature`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_i8(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_i8(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_i8(future) }, + // lift function + { FfiConverterBoolean.lift(it) }, + // Error FFI converter + UniffiNullRustCallStatusErrorHandler, + ) + } + + + + + + + + + /** + * @suppress + */ + companion object + +} + + + +// Put the implementation in an object so we don't pollute the top-level namespace +internal object uniffiCallbackInterfaceSignatureCustomVerify { + internal object `verify`: UniffiCallbackInterfaceSignatureCustomVerifyMethod0 { + override fun callback(`uniffiHandle`: Long,`message`: RustBuffer.ByValue,`signature`: RustBuffer.ByValue,`uniffiFutureCallback`: UniffiForeignFutureCompleteI8,`uniffiCallbackData`: Long,`uniffiOutDroppedCallback`: UniffiForeignFutureDroppedCallbackStruct,) { + val uniffiObj = FfiConverterTypeSignatureCustomVerify.handleMap.get(uniffiHandle) + val makeCall = suspend { -> + uniffiObj.`verify`( + FfiConverterByteArray.lift(`message`), + FfiConverterString.lift(`signature`), + ) + } + val uniffiHandleSuccess = { returnValue: kotlin.Boolean -> + val uniffiResult = UniffiForeignFutureResultI8.UniffiByValue( + FfiConverterBoolean.lower(returnValue), + UniffiRustCallStatus.ByValue() + ) + uniffiResult.write() + uniffiFutureCallback.callback(uniffiCallbackData, uniffiResult) + } + val uniffiHandleError = { callStatus: UniffiRustCallStatus.ByValue -> + uniffiFutureCallback.callback( + uniffiCallbackData, + UniffiForeignFutureResultI8.UniffiByValue( + 0.toByte(), + callStatus, + ), + ) + } + uniffiTraitInterfaceCallAsync( + makeCall, + uniffiHandleSuccess, + uniffiHandleError, + uniffiOutDroppedCallback + ) + } + } + + internal object uniffiFree: UniffiCallbackInterfaceFree { + override fun callback(handle: Long) { + FfiConverterTypeSignatureCustomVerify.handleMap.remove(handle) + } + } + + internal object uniffiClone: UniffiCallbackInterfaceClone { + override fun callback(handle: Long): Long { + return FfiConverterTypeSignatureCustomVerify.handleMap.clone(handle) + } + } + + internal var vtable = UniffiVTableCallbackInterfaceSignatureCustomVerify.UniffiByValue( + uniffiFree, + uniffiClone, + `verify`, + ) + + // Registers the foreign callback with the Rust side. + // This method is generated for each callback interface. + internal fun register(lib: UniffiLib) { + lib.uniffi_wvb_ffi_fn_init_callback_vtable_signaturecustomverify(vtable) + } +} + +/** + * @suppress + */ +public object FfiConverterTypeSignatureCustomVerify: FfiConverter { + internal val handleMap = UniffiHandleMap() + + override fun lower(value: SignatureCustomVerify): Long { + if (value is SignatureCustomVerifyImpl) { + // Rust-implemented object. Clone the handle and return it + return value.uniffiCloneHandle() + } else { + // Kotlin object, generate a new vtable handle and return that. + return handleMap.insert(value) + } + } + + override fun lift(value: Long): SignatureCustomVerify { + if ((value and 1.toLong()) == 0.toLong()) { + // Rust-generated handle, construct a new class that uses the handle to implement the + // interface + return SignatureCustomVerifyImpl(UniffiWithHandle, value) + } else { + // Kotlin-generated handle, get the object from the handle map + return handleMap.remove(value) + } + } + + override fun read(buf: ByteBuffer): SignatureCustomVerify { + return lift(buf.getLong()) + } + + override fun allocationSize(value: SignatureCustomVerify) = 8UL + + override fun write(value: SignatureCustomVerify, buf: ByteBuffer) { + buf.putLong(lower(value)) + } +} + + +// This template implements a class for working with a Rust struct via a handle +// to the live Rust struct on the other side of the FFI. +// +// There's some subtlety here, because we have to be careful not to operate on a Rust +// struct after it has been dropped, and because we must expose a public API for freeing +// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: +// +// * Each instance holds an opaque handle to the underlying Rust struct. +// Method calls need to read this handle from the object's state and pass it in to +// the Rust FFI. +// +// * When an instance is no longer needed, its handle should be passed to a +// special destructor function provided by the Rust FFI, which will drop the +// underlying Rust struct. +// +// * Given an instance, calling code is expected to call the special +// `destroy` method in order to free it after use, either by calling it explicitly +// or by using a higher-level helper like the `use` method. Failing to do so risks +// leaking the underlying Rust struct. +// +// * We can't assume that calling code will do the right thing, and must be prepared +// to handle Kotlin method calls executing concurrently with or even after a call to +// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. +// +// * We must never allow Rust code to operate on the underlying Rust struct after +// the destructor has been called, and must never call the destructor more than once. +// Doing so may trigger memory unsafety. +// +// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` +// is implemented to call the destructor when the Kotlin object becomes unreachable. +// This is done in a background thread. This is not a panacea, and client code should be aware that +// 1. the thread may starve if some there are objects that have poorly performing +// `drop` methods or do significant work in their `drop` methods. +// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, +// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). +// +// If we try to implement this with mutual exclusion on access to the handle, there is the +// possibility of a race between a method call and a concurrent call to `destroy`: +// +// * Thread A starts a method call, reads the value of the handle, but is interrupted +// before it can pass the handle over the FFI to Rust. +// * Thread B calls `destroy` and frees the underlying Rust struct. +// * Thread A resumes, passing the already-read handle value to Rust and triggering +// a use-after-free. +// +// One possible solution would be to use a `ReadWriteLock`, with each method call taking +// a read lock (and thus allowed to run concurrently) and the special `destroy` method +// taking a write lock (and thus blocking on live method calls). However, we aim not to +// generate methods with any hidden blocking semantics, and a `destroy` method that might +// block if called incorrectly seems to meet that bar. +// +// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track +// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` +// has been called. These are updated according to the following rules: +// +// * The initial value of the counter is 1, indicating a live object with no in-flight calls. +// The initial value for the flag is false. +// +// * At the start of each method call, we atomically check the counter. +// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. +// If it is nonzero them we atomically increment it by 1 and proceed with the method call. +// +// * At the end of each method call, we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// * When `destroy` is called, we atomically flip the flag from false to true. +// If the flag was already true we silently fail. +// Otherwise we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, +// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. +// +// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been +// called *and* all in-flight method calls have completed, avoiding violating any of the expectations +// of the underlying Rust code. +// +// This makes a cleaner a better alternative to _not_ calling `destroy()` as +// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` +// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner +// thread may be starved, and the app will leak memory. +// +// In this case, `destroy`ing manually may be a better solution. +// +// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects +// with Rust peers are reclaimed: +// +// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: +// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: +// 3. The memory is reclaimed when the process terminates. +// +// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 +// + + +/** + * Unified access point for bundles from both the builtin and remote sources. + * + * The remote source takes precedence over the builtin source when both contain + * a bundle with the same name. + */ +public interface SourceInterface { + + suspend fun `fetchBuiltinBundle`(`bundleName`: kotlin.String, `version`: kotlin.String): Bundle + + /** + * Loads the full bundle (header + index + data) for `bundle_name`. + */ + suspend fun `fetchBundle`(`bundleName`: kotlin.String): Bundle + + /** + * Loads only the header and index for `bundle_name`, skipping the data section. + * The returned descriptor does not support [`BundleDescriptor::index`]; use + * [`fetch`](Source::fetch_bundle) when entry data is needed. + */ + suspend fun `fetchDescriptor`(`bundleName`: kotlin.String): BundleDescriptor + + suspend fun `fetchRemoteBundle`(`bundleName`: kotlin.String, `version`: kotlin.String): Bundle + + /** + * Resolves the on-disk path of the builtin bundle `bundle_name` at `version`, + * without checking whether the file exists. + */ + fun `getBuiltinBundleFilepath`(`bundleName`: kotlin.String, `version`: kotlin.String): kotlin.String + + suspend fun `getBuiltinVersionData`(`bundleName`: kotlin.String, `version`: kotlin.String): ManifestVersionData? + + /** + * Resolves the on-disk path of the remote bundle `bundle_name` at `version`, + * without checking whether the file exists. + */ + fun `getRemoteBundleFilepath`(`bundleName`: kotlin.String, `version`: kotlin.String): kotlin.String + + suspend fun `getRemotePreviousVersion`(`bundleName`: kotlin.String): kotlin.String? + + suspend fun `getRemoteStagedVersion`(`bundleName`: kotlin.String): kotlin.String? + + suspend fun `getRemoteVersionData`(`bundleName`: kotlin.String, `version`: kotlin.String): ManifestVersionData? + + suspend fun `getVersion`(`bundleName`: kotlin.String): BundleSourceVersion? + + suspend fun `listBuiltinBundles`(): List + + suspend fun `listBundles`(): List + + suspend fun `listRemoteBundles`(): List + + /** + * Loads (and caches) the descriptor for the current version of `bundle_name`. + * Concurrent calls for the same bundle share a single load (single-flight) and + * return the cached descriptor until the active version changes or + * [`unload_descriptor`](Source::unload) is called. + */ + suspend fun `load`(`bundleName`: kotlin.String): LoadedDescriptor + + suspend fun `pruneRemoteBundle`(`bundleName`: kotlin.String): ManifestPruneResult + + suspend fun `pruneRemoteBundles`(`bundleNames`: List): List + + suspend fun `removeRemoteBundle`(`bundleName`: kotlin.String, `version`: kotlin.String, `force`: kotlin.Boolean? = null): ManifestRemoveResult + + suspend fun `removeRemoteBundles`(`items`: Map): List + + suspend fun `resolveFilepath`(`bundleName`: kotlin.String): kotlin.String + + suspend fun `stageRemoteBundle`(`bundleName`: kotlin.String, `data`: ManifestStageData): ManifestStageResult + + suspend fun `stageRemoteBundles`(`items`: Map): List + + /** + * Drops the cached descriptor for `bundle_name`, if present. Already-returned + * [`LoadedDescriptor`] handles keep working; the next call to [`Self::fetch_descriptor`] + * reloads from disk. Returns `true` if a cached descriptor was removed. + */ + fun `unload`(`bundleName`: kotlin.String): kotlin.Boolean + + suspend fun `updateRemoteVersion`(`bundleName`: kotlin.String, `version`: kotlin.String): ManifestSetCurrentVersionResult + + suspend fun `updateRemoteVersions`(`items`: Map): List + + companion object +} + +/** + * Unified access point for bundles from both the builtin and remote sources. + * + * The remote source takes precedence over the builtin source when both contain + * a bundle with the same name. + */ +open class Source: Disposable, AutoCloseable, SourceInterface +{ + + @Suppress("UNUSED_PARAMETER") + /** + * @suppress + */ + constructor(withHandle: UniffiWithHandle, handle: Long) { + this.handle = handle + this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(handle)) + } + + /** + * @suppress + * + * This constructor can be used to instantiate a fake object. Only used for tests. Any + * attempt to actually use an object constructed this way will fail as there is no + * connected Rust object. + */ + @Suppress("UNUSED_PARAMETER") + constructor(noHandle: NoHandle) { + this.handle = 0 + this.cleanable = null + } + constructor(`config`: SourceConfig) : + this(UniffiWithHandle, + uniffiRustCallWithError(WebviewBundleException) { _status -> + UniffiLib.uniffi_wvb_ffi_fn_constructor_source_new( + + FfiConverterTypeSourceConfig.lower(`config`),_status) +} + ) + + protected val handle: Long + protected val cleanable: UniffiCleaner.Cleanable? + + private val wasDestroyed = AtomicBoolean(false) + private val callCounter = AtomicLong(1) + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } + } + + @Synchronized + override fun close() { + this.destroy() + } + + internal inline fun callWithHandle(block: (handle: Long) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.get() + if (c == 0L) { + throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the handle being freed concurrently. + try { + return block(this.uniffiCloneHandle()) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + cleanable?.clean() + } + } + } + + // Use a static inner class instead of a closure so as not to accidentally + // capture `this` as part of the cleanable's action. + private class UniffiCleanAction(private val handle: Long) : Runnable { + override fun run() { + if (handle == 0.toLong()) { + // Fake object created with `NoHandle`, don't try to free. + return; + } + uniffiRustCall { status -> + UniffiLib.uniffi_wvb_ffi_fn_free_source(handle, status) + } + } + } + + /** + * @suppress + */ + fun uniffiCloneHandle(): Long { + if (handle == 0.toLong()) { + throw InternalException("uniffiCloneHandle() called on NoHandle object"); + } + return uniffiRustCall() { status -> + UniffiLib.uniffi_wvb_ffi_fn_clone_source(handle, status) + } + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `fetchBuiltinBundle`(`bundleName`: kotlin.String, `version`: kotlin.String) : Bundle { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_fetch_builtin_bundle( + uniffiHandle, + FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_u64(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_u64(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_u64(future) }, + // lift function + { FfiConverterTypeBundle.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + /** + * Loads the full bundle (header + index + data) for `bundle_name`. + */ + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `fetchBundle`(`bundleName`: kotlin.String) : Bundle { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_fetch_bundle( + uniffiHandle, + FfiConverterString.lower(`bundleName`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_u64(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_u64(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_u64(future) }, + // lift function + { FfiConverterTypeBundle.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + /** + * Loads only the header and index for `bundle_name`, skipping the data section. + * The returned descriptor does not support [`BundleDescriptor::index`]; use + * [`fetch`](Source::fetch_bundle) when entry data is needed. + */ + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `fetchDescriptor`(`bundleName`: kotlin.String) : BundleDescriptor { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_fetch_descriptor( + uniffiHandle, + FfiConverterString.lower(`bundleName`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_u64(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_u64(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_u64(future) }, + // lift function + { FfiConverterTypeBundleDescriptor.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `fetchRemoteBundle`(`bundleName`: kotlin.String, `version`: kotlin.String) : Bundle { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_fetch_remote_bundle( + uniffiHandle, + FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_u64(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_u64(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_u64(future) }, + // lift function + { FfiConverterTypeBundle.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + /** + * Resolves the on-disk path of the builtin bundle `bundle_name` at `version`, + * without checking whether the file exists. + */ + @Throws(WebviewBundleException::class)override fun `getBuiltinBundleFilepath`(`bundleName`: kotlin.String, `version`: kotlin.String): kotlin.String { + return FfiConverterString.lift( + callWithHandle { + uniffiRustCallWithError(WebviewBundleException) { _status -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_get_builtin_bundle_filepath( + it, + FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`),_status) +} + } + ) + } + + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `getBuiltinVersionData`(`bundleName`: kotlin.String, `version`: kotlin.String) : ManifestVersionData? { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_get_builtin_version_data( + uniffiHandle, + FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterOptionalTypeManifestVersionData.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + /** + * Resolves the on-disk path of the remote bundle `bundle_name` at `version`, + * without checking whether the file exists. + */ + @Throws(WebviewBundleException::class)override fun `getRemoteBundleFilepath`(`bundleName`: kotlin.String, `version`: kotlin.String): kotlin.String { + return FfiConverterString.lift( + callWithHandle { + uniffiRustCallWithError(WebviewBundleException) { _status -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_get_remote_bundle_filepath( + it, + FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`),_status) +} + } + ) + } + + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `getRemotePreviousVersion`(`bundleName`: kotlin.String) : kotlin.String? { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_get_remote_previous_version( + uniffiHandle, + FfiConverterString.lower(`bundleName`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterOptionalString.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `getRemoteStagedVersion`(`bundleName`: kotlin.String) : kotlin.String? { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_get_remote_staged_version( + uniffiHandle, + FfiConverterString.lower(`bundleName`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterOptionalString.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `getRemoteVersionData`(`bundleName`: kotlin.String, `version`: kotlin.String) : ManifestVersionData? { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_get_remote_version_data( + uniffiHandle, + FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterOptionalTypeManifestVersionData.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `getVersion`(`bundleName`: kotlin.String) : BundleSourceVersion? { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_get_version( + uniffiHandle, + FfiConverterString.lower(`bundleName`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterOptionalTypeBundleSourceVersion.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `listBuiltinBundles`() : List { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_list_builtin_bundles( + uniffiHandle, + + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterSequenceTypeSourceListItem.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `listBundles`() : List { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_list_bundles( + uniffiHandle, + + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterSequenceTypeSourceListItem.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `listRemoteBundles`() : List { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_list_remote_bundles( + uniffiHandle, + + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterSequenceTypeSourceListItem.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + /** + * Loads (and caches) the descriptor for the current version of `bundle_name`. + * Concurrent calls for the same bundle share a single load (single-flight) and + * return the cached descriptor until the active version changes or + * [`unload_descriptor`](Source::unload) is called. + */ + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `load`(`bundleName`: kotlin.String) : LoadedDescriptor { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_load( + uniffiHandle, + FfiConverterString.lower(`bundleName`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_u64(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_u64(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_u64(future) }, + // lift function + { FfiConverterTypeLoadedDescriptor.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `pruneRemoteBundle`(`bundleName`: kotlin.String) : ManifestPruneResult { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_prune_remote_bundle( + uniffiHandle, + FfiConverterString.lower(`bundleName`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterTypeManifestPruneResult.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `pruneRemoteBundles`(`bundleNames`: List) : List { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_prune_remote_bundles( + uniffiHandle, + FfiConverterSequenceString.lower(`bundleNames`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterSequenceTypeManifestPruneResult.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `removeRemoteBundle`(`bundleName`: kotlin.String, `version`: kotlin.String, `force`: kotlin.Boolean?) : ManifestRemoveResult { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_remove_remote_bundle( + uniffiHandle, + FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`),FfiConverterOptionalBoolean.lower(`force`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterTypeManifestRemoveResult.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) } - @Synchronized - override fun close() { - this.destroy() + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `removeRemoteBundles`(`items`: Map) : List { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_remove_remote_bundles( + uniffiHandle, + FfiConverterMapStringTypeManifestRemoveData.lower(`items`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterSequenceTypeManifestRemoveResult.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) } - internal inline fun callWithHandle(block: (handle: Long) -> R): R { - // Check and increment the call counter, to keep the object alive. - // This needs a compare-and-set retry loop in case of concurrent updates. - do { - val c = this.callCounter.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") - } - } while (! this.callCounter.compareAndSet(c, c + 1L)) - // Now we can safely do the method call without the handle being freed concurrently. - try { - return block(this.uniffiCloneHandle()) - } finally { - // This decrement always matches the increment we performed above. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `resolveFilepath`(`bundleName`: kotlin.String) : kotlin.String { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_resolve_filepath( + uniffiHandle, + FfiConverterString.lower(`bundleName`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterString.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) } - // Use a static inner class instead of a closure so as not to accidentally - // capture `this` as part of the cleanable's action. - private class UniffiCleanAction(private val handle: Long) : Runnable { - override fun run() { - if (handle == 0.toLong()) { - // Fake object created with `NoHandle`, don't try to free. - return; - } - uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_loadeddescriptor(handle, status) - } - } + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `stageRemoteBundle`(`bundleName`: kotlin.String, `data`: ManifestStageData) : ManifestStageResult { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_stage_remote_bundle( + uniffiHandle, + FfiConverterString.lower(`bundleName`),FfiConverterTypeManifestStageData.lower(`data`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterTypeManifestStageResult.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) } - /** - * @suppress - */ - fun uniffiCloneHandle(): Long { - if (handle == 0.toLong()) { - throw InternalException("uniffiCloneHandle() called on NoHandle object"); - } - return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_loadeddescriptor(handle, status) - } + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `stageRemoteBundles`(`items`: Map) : List { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_source_stage_remote_bundles( + uniffiHandle, + FfiConverterMapStringTypeManifestStageData.lower(`items`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterSequenceTypeManifestStageResult.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) } /** - * Returns the bundle descriptor (header + index metadata). - * - * The returned descriptor carries no reference back to the source, so it can - * outlive this `LoadedDescriptor`. It holds only metadata, so its `index()` is - * unsupported; use [`get_data`](LoadedDescriptor::get_data) for entry data. - */override fun `descriptor`(): BundleDescriptor { - return FfiConverterTypeBundleDescriptor.lift( + * Drops the cached descriptor for `bundle_name`, if present. Already-returned + * [`LoadedDescriptor`] handles keep working; the next call to [`Self::fetch_descriptor`] + * reloads from disk. Returns `true` if a cached descriptor was removed. + */override fun `unload`(`bundleName`: kotlin.String): kotlin.Boolean { + return FfiConverterBoolean.lift( callWithHandle { uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_loadeddescriptor_descriptor( + UniffiLib.uniffi_wvb_ffi_fn_method_source_unload( it, - _status) + FfiConverterString.lower(`bundleName`),_status) } } ) @@ -5660,54 +7395,42 @@ open class LoadedDescriptor: Disposable, AutoCloseable, LoadedDescriptorInterfac - /** - * Reads the bytes for `path`, loading them lazily from disk. - * - * The read targets the bundle file this descriptor was loaded from, so the data - * stays consistent with [`descriptor`](LoadedDescriptor::descriptor) even if the - * source's active version changes meanwhile. Returns `None` if `path` does not - * exist in the bundle. - */ @Throws(WebviewBundleException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `getData`(`path`: kotlin.String) : kotlin.ByteArray? { + override suspend fun `updateRemoteVersion`(`bundleName`: kotlin.String, `version`: kotlin.String) : ManifestSetCurrentVersionResult { return uniffiRustCallAsync( callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_loadeddescriptor_get_data( + UniffiLib.uniffi_wvb_ffi_fn_method_source_update_remote_version( uniffiHandle, - FfiConverterString.lower(`path`), + FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), ) }, { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, // lift function - { FfiConverterOptionalByteArray.lift(it) }, + { FfiConverterTypeManifestSetCurrentVersionResult.lift(it) }, // Error FFI converter WebviewBundleException.ErrorHandler, ) } - /** - * Reads the xxHash-32 checksum for `path`, loading it lazily from disk. - * Returns `None` if `path` does not exist in the bundle. - */ @Throws(WebviewBundleException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `getDataChecksum`(`path`: kotlin.String) : kotlin.UInt? { + override suspend fun `updateRemoteVersions`(`items`: Map) : List { return uniffiRustCallAsync( callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_loadeddescriptor_get_data_checksum( + UniffiLib.uniffi_wvb_ffi_fn_method_source_update_remote_versions( uniffiHandle, - FfiConverterString.lower(`path`), + FfiConverterMapStringString.lower(`items`), ) }, { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, // lift function - { FfiConverterOptionalUInt.lift(it) }, + { FfiConverterSequenceTypeManifestSetCurrentVersionResult.lift(it) }, // Error FFI converter WebviewBundleException.ErrorHandler, ) @@ -5731,22 +7454,22 @@ open class LoadedDescriptor: Disposable, AutoCloseable, LoadedDescriptorInterfac /** * @suppress */ -public object FfiConverterTypeLoadedDescriptor: FfiConverter { - override fun lower(value: LoadedDescriptor): Long { +public object FfiConverterTypeSource: FfiConverter { + override fun lower(value: Source): Long { return value.uniffiCloneHandle() } - override fun lift(value: Long): LoadedDescriptor { - return LoadedDescriptor(UniffiWithHandle, value) + override fun lift(value: Long): Source { + return Source(UniffiWithHandle, value) } - override fun read(buf: ByteBuffer): LoadedDescriptor { + override fun read(buf: ByteBuffer): Source { return lift(buf.getLong()) } - override fun allocationSize(value: LoadedDescriptor) = 8UL + override fun allocationSize(value: Source) = 8UL - override fun write(value: LoadedDescriptor, buf: ByteBuffer) { + override fun write(value: Source, buf: ByteBuffer) { buf.putLong(lower(value)) } } @@ -5848,30 +7571,27 @@ public object FfiConverterTypeLoadedDescriptor: FfiConverter? = null, `body`: kotlin.ByteArray? = null): HttpResponse + suspend fun `download`(`bundleUpdates`: List, `options`: UpdaterDownloadOptions? = null): List + + suspend fun `getUpdate`(`options`: UpdaterGetUpdateOptions? = null): Update? + + suspend fun `install`(`targets`: List): List + + suspend fun `rollback`(`targets`: List): List companion object } /** - * Proxies HTTP-like requests to another HTTP server (typically a local dev server). - * - * The target is resolved per request — either from a static host mapping - * (e.g. `{"myapp": "http://localhost:8080"}`, keyed by uri host) or by a custom - * [`ProxyResolver`]. A request whose target cannot be resolved fails with an error. + * Orchestrates the full update cycle: checks for a new version on the remote, + * downloads it, verifies integrity/signature, and writes it to the local source. */ -open class ProxyProtocolHandler: Disposable, AutoCloseable, ProxyProtocolHandlerInterface +open class Updater: Disposable, AutoCloseable, UpdaterInterface { @Suppress("UNUSED_PARAMETER") @@ -5895,15 +7615,12 @@ open class ProxyProtocolHandler: Disposable, AutoCloseable, ProxyProtocolHandler this.handle = 0 this.cleanable = null } - /** - * Proxy by a static host mapping, keyed by the uri host. - */ - constructor(`hosts`: Map) : + constructor(`source`: Source, `remote`: Remote, `updateFilepath`: kotlin.String, `options`: UpdaterOptions?) : this(UniffiWithHandle, - uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_constructor_proxyprotocolhandler_new( + uniffiRustCallWithError(WebviewBundleException) { _status -> + UniffiLib.uniffi_wvb_ffi_fn_constructor_updater_new( - FfiConverterMapStringString.lower(`hosts`),_status) + FfiConverterTypeSource.lower(`source`),FfiConverterTypeRemote.lower(`remote`),FfiConverterString.lower(`updateFilepath`),FfiConverterOptionalTypeUpdaterOptions.lower(`options`),_status) } ) @@ -5961,7 +7678,7 @@ open class ProxyProtocolHandler: Disposable, AutoCloseable, ProxyProtocolHandler return; } uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_proxyprotocolhandler(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_free_updater(handle, status) } } } @@ -5974,29 +7691,89 @@ open class ProxyProtocolHandler: Disposable, AutoCloseable, ProxyProtocolHandler throw InternalException("uniffiCloneHandle() called on NoHandle object"); } return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_proxyprotocolhandler(handle, status) + UniffiLib.uniffi_wvb_ffi_fn_clone_updater(handle, status) } } - /** - * Forwards the request — including `body`, for POST/PUT/PATCH — to the resolved target. - */ @Throws(WebviewBundleException::class) @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `handle`(`method`: HttpMethod, `uri`: kotlin.String, `headers`: Map?, `body`: kotlin.ByteArray?) : HttpResponse { + override suspend fun `download`(`bundleUpdates`: List, `options`: UpdaterDownloadOptions?) : List { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_updater_download( + uniffiHandle, + FfiConverterSequenceTypeBundleUpdate.lower(`bundleUpdates`),FfiConverterOptionalTypeUpdaterDownloadOptions.lower(`options`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterSequenceTypeUpdaterDownloadResult.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `getUpdate`(`options`: UpdaterGetUpdateOptions?) : Update? { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_updater_get_update( + uniffiHandle, + FfiConverterOptionalTypeUpdaterGetUpdateOptions.lower(`options`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterOptionalTypeUpdate.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `install`(`targets`: List) : List { return uniffiRustCallAsync( callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_proxyprotocolhandler_handle( + UniffiLib.uniffi_wvb_ffi_fn_method_updater_install( uniffiHandle, - FfiConverterTypeHttpMethod.lower(`method`),FfiConverterString.lower(`uri`),FfiConverterOptionalMapStringString.lower(`headers`),FfiConverterOptionalByteArray.lower(`body`), + FfiConverterSequenceTypeUpdaterInstallTarget.lower(`targets`), ) }, { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, // lift function - { FfiConverterTypeHttpResponse.lift(it) }, + { FfiConverterSequenceTypeUpdaterInstallResult.lift(it) }, + // Error FFI converter + WebviewBundleException.ErrorHandler, + ) + } + + + @Throws(WebviewBundleException::class) + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun `rollback`(`targets`: List) : List { + return uniffiRustCallAsync( + callWithHandle { uniffiHandle -> + UniffiLib.uniffi_wvb_ffi_fn_method_updater_rollback( + uniffiHandle, + FfiConverterSequenceTypeUpdaterRollbackTarget.lower(`targets`), + ) + }, + { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, + { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, + { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, + // lift function + { FfiConverterSequenceTypeUpdaterRollbackResult.lift(it) }, // Error FFI converter WebviewBundleException.ErrorHandler, ) @@ -6008,1783 +7785,1537 @@ open class ProxyProtocolHandler: Disposable, AutoCloseable, ProxyProtocolHandler - companion object { - + /** - * Proxy by a custom resolver. - */ fun `custom`(`resolver`: ProxyResolver): ProxyProtocolHandler { - return FfiConverterTypeProxyProtocolHandler.lift( - uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_constructor_proxyprotocolhandler_custom( + * @suppress + */ + companion object - FfiConverterTypeProxyResolver.lower(`resolver`),_status) } - ) + + +/** + * @suppress + */ +public object FfiConverterTypeUpdater: FfiConverter { + override fun lower(value: Updater): Long { + return value.uniffiCloneHandle() } - - + override fun lift(value: Long): Updater { + return Updater(UniffiWithHandle, value) + } + + override fun read(buf: ByteBuffer): Updater { + return lift(buf.getLong()) + } + + override fun allocationSize(value: Updater) = 8UL + + override fun write(value: Updater, buf: ByteBuffer) { + buf.putLong(lower(value)) } - } + +/** + * Options for the bundle header section. + */ +data class BuildHeaderOptions ( + var `checksum`: ChecksumWriteOptions? = null + +){ + + + + + + companion object +} + /** * @suppress */ -public object FfiConverterTypeProxyProtocolHandler: FfiConverter { - override fun lower(value: ProxyProtocolHandler): Long { - return value.uniffiCloneHandle() +public object FfiConverterTypeBuildHeaderOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BuildHeaderOptions { + return BuildHeaderOptions( + FfiConverterOptionalTypeChecksumWriteOptions.read(buf), + ) } - override fun lift(value: Long): ProxyProtocolHandler { - return ProxyProtocolHandler(UniffiWithHandle, value) + override fun allocationSize(value: BuildHeaderOptions) = ( + FfiConverterOptionalTypeChecksumWriteOptions.allocationSize(value.`checksum`) + ) + + override fun write(value: BuildHeaderOptions, buf: ByteBuffer) { + FfiConverterOptionalTypeChecksumWriteOptions.write(value.`checksum`, buf) } +} - override fun read(buf: ByteBuffer): ProxyProtocolHandler { - return lift(buf.getLong()) + + +/** + * Pptions for the bundle index section. + */ +data class BuildIndexOptions ( + var `checksum`: ChecksumWriteOptions? = null + +){ + + + + + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeBuildIndexOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BuildIndexOptions { + return BuildIndexOptions( + FfiConverterOptionalTypeChecksumWriteOptions.read(buf), + ) } - override fun allocationSize(value: ProxyProtocolHandler) = 8UL + override fun allocationSize(value: BuildIndexOptions) = ( + FfiConverterOptionalTypeChecksumWriteOptions.allocationSize(value.`checksum`) + ) - override fun write(value: ProxyProtocolHandler, buf: ByteBuffer) { - buf.putLong(lower(value)) + override fun write(value: BuildIndexOptions, buf: ByteBuffer) { + FfiConverterOptionalTypeChecksumWriteOptions.write(value.`checksum`, buf) } } -// This template implements a class for working with a Rust struct via a handle -// to the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque handle to the underlying Rust struct. -// Method calls need to read this handle from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its handle should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the handle, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the handle, but is interrupted -// before it can pass the handle over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read handle value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// + +/** + * Top-level options passed to [`BundleBuilder::build`]. + * All fields are optional; omitting them applies the library defaults. + */ +data class BuildOptions ( + var `header`: BuildHeaderOptions? + , + var `index`: BuildIndexOptions? + , + var `dataChecksum`: ChecksumWriteOptions? + +){ + + + + + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeBuildOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BuildOptions { + return BuildOptions( + FfiConverterOptionalTypeBuildHeaderOptions.read(buf), + FfiConverterOptionalTypeBuildIndexOptions.read(buf), + FfiConverterOptionalTypeChecksumWriteOptions.read(buf), + ) + } + + override fun allocationSize(value: BuildOptions) = ( + FfiConverterOptionalTypeBuildHeaderOptions.allocationSize(value.`header`) + + FfiConverterOptionalTypeBuildIndexOptions.allocationSize(value.`index`) + + FfiConverterOptionalTypeChecksumWriteOptions.allocationSize(value.`dataChecksum`) + ) + + override fun write(value: BuildOptions, buf: ByteBuffer) { + FfiConverterOptionalTypeBuildHeaderOptions.write(value.`header`, buf) + FfiConverterOptionalTypeBuildIndexOptions.write(value.`index`, buf) + FfiConverterOptionalTypeChecksumWriteOptions.write(value.`dataChecksum`, buf) + } +} + /** - * Resolves the proxy target for a request uri, e.g. `http://localhost:3000`. + * How a [`BundleProtocolHandler`] resolves the request uri. * - * The path and query of the request are appended to the returned target. Return `null` to - * not proxy the request; the handler then fails with `CannotResolveProxyServer`. + * Defaults to the first hostname segment as the bundle name, and a directory-index path + * (`/about` -> `/about/index.html`). */ -public interface ProxyResolver { +data class BundleProtocolOptions ( + var `bundleResolver`: BundleResolver? = null + , + var `pathResolver`: PathResolver? = null - suspend fun `resolve`(`uri`: kotlin.String): kotlin.String? +){ + + + + companion object } /** - * Resolves the proxy target for a request uri, e.g. `http://localhost:3000`. - * - * The path and query of the request are appended to the returned target. Return `null` to - * not proxy the request; the handler then fails with `CannotResolveProxyServer`. + * @suppress */ -open class ProxyResolverImpl: Disposable, AutoCloseable, ProxyResolver -{ - - @Suppress("UNUSED_PARAMETER") - /** - * @suppress - */ - constructor(withHandle: UniffiWithHandle, handle: Long) { - this.handle = handle - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(handle)) +public object FfiConverterTypeBundleProtocolOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BundleProtocolOptions { + return BundleProtocolOptions( + FfiConverterOptionalTypeBundleResolver.read(buf), + FfiConverterOptionalTypePathResolver.read(buf), + ) } - /** - * @suppress - * - * This constructor can be used to instantiate a fake object. Only used for tests. Any - * attempt to actually use an object constructed this way will fail as there is no - * connected Rust object. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noHandle: NoHandle) { - this.handle = 0 - this.cleanable = null + override fun allocationSize(value: BundleProtocolOptions) = ( + FfiConverterOptionalTypeBundleResolver.allocationSize(value.`bundleResolver`) + + FfiConverterOptionalTypePathResolver.allocationSize(value.`pathResolver`) + ) + + override fun write(value: BundleProtocolOptions, buf: ByteBuffer) { + FfiConverterOptionalTypeBundleResolver.write(value.`bundleResolver`, buf) + FfiConverterOptionalTypePathResolver.write(value.`pathResolver`, buf) } +} - protected val handle: Long - protected val cleanable: UniffiCleaner.Cleanable? - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - override fun destroy() { - // Only allow a single call to this method. - // TODO: maybe we should log a warning if called more than once? - if (this.wasDestroyed.compareAndSet(false, true)) { - // This decrement always matches the initial count of 1 given at creation time. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } - } +/** + * The currently active version of a bundle and where it was loaded from. + */ +data class BundleSourceVersion ( + var `source`: SourceKind + , + var `version`: kotlin.String + +){ + - @Synchronized - override fun close() { - this.destroy() - } + - internal inline fun callWithHandle(block: (handle: Long) -> R): R { - // Check and increment the call counter, to keep the object alive. - // This needs a compare-and-set retry loop in case of concurrent updates. - do { - val c = this.callCounter.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") - } - } while (! this.callCounter.compareAndSet(c, c + 1L)) - // Now we can safely do the method call without the handle being freed concurrently. - try { - return block(this.uniffiCloneHandle()) - } finally { - // This decrement always matches the increment we performed above. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeBundleSourceVersion: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BundleSourceVersion { + return BundleSourceVersion( + FfiConverterTypeSourceKind.read(buf), + FfiConverterString.read(buf), + ) } - // Use a static inner class instead of a closure so as not to accidentally - // capture `this` as part of the cleanable's action. - private class UniffiCleanAction(private val handle: Long) : Runnable { - override fun run() { - if (handle == 0.toLong()) { - // Fake object created with `NoHandle`, don't try to free. - return; - } - uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_proxyresolver(handle, status) - } - } + override fun allocationSize(value: BundleSourceVersion) = ( + FfiConverterTypeSourceKind.allocationSize(value.`source`) + + FfiConverterString.allocationSize(value.`version`) + ) + + override fun write(value: BundleSourceVersion, buf: ByteBuffer) { + FfiConverterTypeSourceKind.write(value.`source`, buf) + FfiConverterString.write(value.`version`, buf) } +} + + +/** + * A bundle advertised by an update document. + */ +data class BundleUpdate ( /** - * @suppress + * Bundle name. */ - fun uniffiCloneHandle(): Long { - if (handle == 0.toLong()) { - throw InternalException("uniffiCloneHandle() called on NoHandle object"); - } - return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_proxyresolver(handle, status) - } - } - + var `name`: kotlin.String + , + /** + * Bundle version. + */ + var `version`: kotlin.String + , + /** + * Absolute download URL when the server overrides the default endpoint. + */ + var `downloadUrl`: kotlin.String? + , + /** + * Serialized integrity value for the downloaded bundle. + */ + var `integrity`: kotlin.String? + , + /** + * Provider-defined, string-valued bundle metadata. + */ + var `metadata`: Map? - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `resolve`(`uri`: kotlin.String) : kotlin.String? { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_proxyresolver_resolve( - uniffiHandle, - FfiConverterString.lower(`uri`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterOptionalString.lift(it) }, - // Error FFI converter - UniffiNullRustCallStatusErrorHandler, - ) - } - +){ - - - /** - * @suppress - */ companion object - } - - -// Put the implementation in an object so we don't pollute the top-level namespace -internal object uniffiCallbackInterfaceProxyResolver { - internal object `resolve`: UniffiCallbackInterfaceProxyResolverMethod0 { - override fun callback(`uniffiHandle`: Long,`uri`: RustBuffer.ByValue,`uniffiFutureCallback`: UniffiForeignFutureCompleteRustBuffer,`uniffiCallbackData`: Long,`uniffiOutDroppedCallback`: UniffiForeignFutureDroppedCallbackStruct,) { - val uniffiObj = FfiConverterTypeProxyResolver.handleMap.get(uniffiHandle) - val makeCall = suspend { -> - uniffiObj.`resolve`( - FfiConverterString.lift(`uri`), - ) - } - val uniffiHandleSuccess = { returnValue: kotlin.String? -> - val uniffiResult = UniffiForeignFutureResultRustBuffer.UniffiByValue( - FfiConverterOptionalString.lower(returnValue), - UniffiRustCallStatus.ByValue() - ) - uniffiResult.write() - uniffiFutureCallback.callback(uniffiCallbackData, uniffiResult) - } - val uniffiHandleError = { callStatus: UniffiRustCallStatus.ByValue -> - uniffiFutureCallback.callback( - uniffiCallbackData, - UniffiForeignFutureResultRustBuffer.UniffiByValue( - RustBuffer.ByValue(), - callStatus, - ), - ) - } - uniffiTraitInterfaceCallAsync( - makeCall, - uniffiHandleSuccess, - uniffiHandleError, - uniffiOutDroppedCallback - ) - } +/** + * @suppress + */ +public object FfiConverterTypeBundleUpdate: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BundleUpdate { + return BundleUpdate( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalMapStringString.read(buf), + ) } - internal object uniffiFree: UniffiCallbackInterfaceFree { - override fun callback(handle: Long) { - FfiConverterTypeProxyResolver.handleMap.remove(handle) - } - } + override fun allocationSize(value: BundleUpdate) = ( + FfiConverterString.allocationSize(value.`name`) + + FfiConverterString.allocationSize(value.`version`) + + FfiConverterOptionalString.allocationSize(value.`downloadUrl`) + + FfiConverterOptionalString.allocationSize(value.`integrity`) + + FfiConverterOptionalMapStringString.allocationSize(value.`metadata`) + ) - internal object uniffiClone: UniffiCallbackInterfaceClone { - override fun callback(handle: Long): Long { - return FfiConverterTypeProxyResolver.handleMap.clone(handle) - } + override fun write(value: BundleUpdate, buf: ByteBuffer) { + FfiConverterString.write(value.`name`, buf) + FfiConverterString.write(value.`version`, buf) + FfiConverterOptionalString.write(value.`downloadUrl`, buf) + FfiConverterOptionalString.write(value.`integrity`, buf) + FfiConverterOptionalMapStringString.write(value.`metadata`, buf) } +} - internal var vtable = UniffiVTableCallbackInterfaceProxyResolver.UniffiByValue( - uniffiFree, - uniffiClone, - `resolve`, - ) - // Registers the foreign callback with the Rust side. - // This method is generated for each callback interface. - internal fun register(lib: UniffiLib) { - lib.uniffi_wvb_ffi_fn_init_callback_vtable_proxyresolver(vtable) - } + +/** + * How each entry's xxHash-32 data checksum is verified when its data is read. + */ +data class ChecksumReadOptions ( + /** + * Verify each entry's data checksum when its data is read (default: `true`). + */ + var `verify`: kotlin.Boolean? = null + , + /** + * The seed the data checksums were built with (default: `0`). + */ + var `seed`: kotlin.UInt? = null + +){ + + + + + + companion object } /** * @suppress */ -public object FfiConverterTypeProxyResolver: FfiConverter { - internal val handleMap = UniffiHandleMap() - - override fun lower(value: ProxyResolver): Long { - if (value is ProxyResolverImpl) { - // Rust-implemented object. Clone the handle and return it - return value.uniffiCloneHandle() - } else { - // Kotlin object, generate a new vtable handle and return that. - return handleMap.insert(value) - } +public object FfiConverterTypeChecksumReadOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChecksumReadOptions { + return ChecksumReadOptions( + FfiConverterOptionalBoolean.read(buf), + FfiConverterOptionalUInt.read(buf), + ) } - override fun lift(value: Long): ProxyResolver { - if ((value and 1.toLong()) == 0.toLong()) { - // Rust-generated handle, construct a new class that uses the handle to implement the - // interface - return ProxyResolverImpl(UniffiWithHandle, value) - } else { - // Kotlin-generated handle, get the object from the handle map - return handleMap.remove(value) - } + override fun allocationSize(value: ChecksumReadOptions) = ( + FfiConverterOptionalBoolean.allocationSize(value.`verify`) + + FfiConverterOptionalUInt.allocationSize(value.`seed`) + ) + + override fun write(value: ChecksumReadOptions, buf: ByteBuffer) { + FfiConverterOptionalBoolean.write(value.`verify`, buf) + FfiConverterOptionalUInt.write(value.`seed`, buf) } +} - override fun read(buf: ByteBuffer): ProxyResolver { - return lift(buf.getLong()) + + +data class ChecksumWriteOptions ( + /** + * The seed the data checksums were built with (default: `0`). + */ + var `seed`: kotlin.UInt? = null + +){ + + + + + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeChecksumWriteOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChecksumWriteOptions { + return ChecksumWriteOptions( + FfiConverterOptionalUInt.read(buf), + ) } - override fun allocationSize(value: ProxyResolver) = 8UL + override fun allocationSize(value: ChecksumWriteOptions) = ( + FfiConverterOptionalUInt.allocationSize(value.`seed`) + ) - override fun write(value: ProxyResolver, buf: ByteBuffer) { - buf.putLong(lower(value)) + override fun write(value: ChecksumWriteOptions, buf: ByteBuffer) { + FfiConverterOptionalUInt.write(value.`seed`, buf) } } -// This template implements a class for working with a Rust struct via a handle -// to the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque handle to the underlying Rust struct. -// Method calls need to read this handle from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its handle should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the handle, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the handle, but is interrupted -// before it can pass the handle over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read handle value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - /** - * HTTP client for a WebViewBundle remote server. + * How each entry's data checksum is verified when its data is read. */ -public interface RemoteInterface { - - suspend fun `download`(`bundleName`: kotlin.String, `channel`: kotlin.String?): DownloadResult - - suspend fun `downloadVersion`(`bundleName`: kotlin.String, `version`: kotlin.String): DownloadResult - +data class DataReadOptions ( /** - * Fetches metadata for the latest version of `bundle_name` without downloading the bundle. + * How each entry's data checksum is verified. */ - suspend fun `getInfo`(`bundleName`: kotlin.String, `options`: RemoteFetchOptions?): RemoteBundleInfo + var `checksum`: ChecksumReadOptions? = null + +){ + + - suspend fun `listBundles`(`options`: RemoteFetchOptions?): List + companion object } /** - * HTTP client for a WebViewBundle remote server. + * @suppress */ -open class Remote: Disposable, AutoCloseable, RemoteInterface -{ - - @Suppress("UNUSED_PARAMETER") - /** - * @suppress - */ - constructor(withHandle: UniffiWithHandle, handle: Long) { - this.handle = handle - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(handle)) +public object FfiConverterTypeDataReadOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): DataReadOptions { + return DataReadOptions( + FfiConverterOptionalTypeChecksumReadOptions.read(buf), + ) } - /** - * @suppress - * - * This constructor can be used to instantiate a fake object. Only used for tests. Any - * attempt to actually use an object constructed this way will fail as there is no - * connected Rust object. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noHandle: NoHandle) { - this.handle = 0 - this.cleanable = null + override fun allocationSize(value: DataReadOptions) = ( + FfiConverterOptionalTypeChecksumReadOptions.allocationSize(value.`checksum`) + ) + + override fun write(value: DataReadOptions, buf: ByteBuffer) { + FfiConverterOptionalTypeChecksumReadOptions.write(value.`checksum`, buf) } +} + + + +/** + * How a bundle's header checksum is verified when its header is read. + */ +data class HeaderReadOptions ( /** - * Creates a client for the server at `endpoint` (e.g. `"https://bundles.example.com"`). + * How the header checksum is verified. */ - constructor(`endpoint`: kotlin.String, `options`: RemoteOptions? = null) : - this(UniffiWithHandle, - uniffiRustCallWithError(WebviewBundleException) { _status -> - UniffiLib.uniffi_wvb_ffi_fn_constructor_remote_new( + var `checksum`: ChecksumReadOptions? = null + +){ - FfiConverterString.lower(`endpoint`),FfiConverterOptionalTypeRemoteOptions.lower(`options`),_status) -} - ) - protected val handle: Long - protected val cleanable: UniffiCleaner.Cleanable? + - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) + + companion object +} - override fun destroy() { - // Only allow a single call to this method. - // TODO: maybe we should log a warning if called more than once? - if (this.wasDestroyed.compareAndSet(false, true)) { - // This decrement always matches the initial count of 1 given at creation time. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } +/** + * @suppress + */ +public object FfiConverterTypeHeaderReadOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): HeaderReadOptions { + return HeaderReadOptions( + FfiConverterOptionalTypeChecksumReadOptions.read(buf), + ) } - @Synchronized - override fun close() { - this.destroy() - } + override fun allocationSize(value: HeaderReadOptions) = ( + FfiConverterOptionalTypeChecksumReadOptions.allocationSize(value.`checksum`) + ) - internal inline fun callWithHandle(block: (handle: Long) -> R): R { - // Check and increment the call counter, to keep the object alive. - // This needs a compare-and-set retry loop in case of concurrent updates. - do { - val c = this.callCounter.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") - } - } while (! this.callCounter.compareAndSet(c, c + 1L)) - // Now we can safely do the method call without the handle being freed concurrently. - try { - return block(this.uniffiCloneHandle()) - } finally { - // This decrement always matches the increment we performed above. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } + override fun write(value: HeaderReadOptions, buf: ByteBuffer) { + FfiConverterOptionalTypeChecksumReadOptions.write(value.`checksum`, buf) } +} - // Use a static inner class instead of a closure so as not to accidentally - // capture `this` as part of the cleanable's action. - private class UniffiCleanAction(private val handle: Long) : Runnable { - override fun run() { - if (handle == 0.toLong()) { - // Fake object created with `NoHandle`, don't try to free. - return; - } - uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_remote(handle, status) - } - } - } + +/** + * HTTP client options + */ +data class HttpOptions ( /** - * @suppress + * Headers sent with every request. */ - fun uniffiCloneHandle(): Long { - if (handle == 0.toLong()) { - throw InternalException("uniffiCloneHandle() called on NoHandle object"); - } - return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_remote(handle, status) - } - } - + var `defaultHeaders`: Map? = null + , + /** + * User-Agent sent with requests, when supplied. + */ + var `userAgent`: kotlin.String? = null + , + /** + * Total request timeout in milliseconds (default: `120000`). + * + * Bounds an otherwise-unbounded download: without it a stalled transfer would hang + * forever and keep holding the updater's per-bundle lock. + */ + var `timeout`: kotlin.ULong? = null + , + /** + * Timeout in milliseconds for reading the response body. + */ + var `readTimeout`: kotlin.ULong? = null + , + /** + * Timeout in milliseconds for establishing the connection. + */ + var `connectTimeout`: kotlin.ULong? = null + , + /** + * Idle lifetime in milliseconds for pooled connections. + */ + var `poolIdleTimeout`: kotlin.ULong? = null + , + /** + * Maximum idle connections retained for a host. + */ + var `poolMaxIdlePerHost`: kotlin.UInt? = null + , + /** + * Whether to generate a Referer header on redirects. + */ + var `referer`: kotlin.Boolean? = null + , + /** + * Whether to disable Nagle's algorithm on TCP sockets. + */ + var `tcpNodelay`: kotlin.Boolean? = null + +){ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `download`(`bundleName`: kotlin.String, `channel`: kotlin.String?) : DownloadResult { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_remote_download( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterOptionalString.lower(`channel`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterTypeDownloadResult.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) - } - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `downloadVersion`(`bundleName`: kotlin.String, `version`: kotlin.String) : DownloadResult { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_remote_download_version( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterTypeDownloadResult.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) - } - /** - * Fetches metadata for the latest version of `bundle_name` without downloading the bundle. - */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `getInfo`(`bundleName`: kotlin.String, `options`: RemoteFetchOptions?) : RemoteBundleInfo { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_remote_get_info( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterOptionalTypeRemoteFetchOptions.lower(`options`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterTypeRemoteBundleInfo.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeHttpOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): HttpOptions { + return HttpOptions( + FfiConverterOptionalMapStringString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalUInt.read(buf), + FfiConverterOptionalBoolean.read(buf), + FfiConverterOptionalBoolean.read(buf), + ) } - - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `listBundles`(`options`: RemoteFetchOptions?) : List { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_remote_list_bundles( - uniffiHandle, - FfiConverterOptionalTypeRemoteFetchOptions.lower(`options`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterSequenceTypeListRemoteBundleInfo.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, + override fun allocationSize(value: HttpOptions) = ( + FfiConverterOptionalMapStringString.allocationSize(value.`defaultHeaders`) + + FfiConverterOptionalString.allocationSize(value.`userAgent`) + + FfiConverterOptionalULong.allocationSize(value.`timeout`) + + FfiConverterOptionalULong.allocationSize(value.`readTimeout`) + + FfiConverterOptionalULong.allocationSize(value.`connectTimeout`) + + FfiConverterOptionalULong.allocationSize(value.`poolIdleTimeout`) + + FfiConverterOptionalUInt.allocationSize(value.`poolMaxIdlePerHost`) + + FfiConverterOptionalBoolean.allocationSize(value.`referer`) + + FfiConverterOptionalBoolean.allocationSize(value.`tcpNodelay`) ) + + override fun write(value: HttpOptions, buf: ByteBuffer) { + FfiConverterOptionalMapStringString.write(value.`defaultHeaders`, buf) + FfiConverterOptionalString.write(value.`userAgent`, buf) + FfiConverterOptionalULong.write(value.`timeout`, buf) + FfiConverterOptionalULong.write(value.`readTimeout`, buf) + FfiConverterOptionalULong.write(value.`connectTimeout`, buf) + FfiConverterOptionalULong.write(value.`poolIdleTimeout`, buf) + FfiConverterOptionalUInt.write(value.`poolMaxIdlePerHost`, buf) + FfiConverterOptionalBoolean.write(value.`referer`, buf) + FfiConverterOptionalBoolean.write(value.`tcpNodelay`, buf) } +} + + +/** + * HTTP response returned by protocol handlers. + */ +data class HttpResponse ( + var `status`: kotlin.UShort + , + var `headers`: Map + , + var `body`: kotlin.ByteArray - +){ - + - /** - * @suppress - */ companion object - } - /** * @suppress */ -public object FfiConverterTypeRemote: FfiConverter { - override fun lower(value: Remote): Long { - return value.uniffiCloneHandle() - } - - override fun lift(value: Long): Remote { - return Remote(UniffiWithHandle, value) - } - - override fun read(buf: ByteBuffer): Remote { - return lift(buf.getLong()) +public object FfiConverterTypeHttpResponse: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): HttpResponse { + return HttpResponse( + FfiConverterUShort.read(buf), + FfiConverterMapStringString.read(buf), + FfiConverterByteArray.read(buf), + ) } - override fun allocationSize(value: Remote) = 8UL + override fun allocationSize(value: HttpResponse) = ( + FfiConverterUShort.allocationSize(value.`status`) + + FfiConverterMapStringString.allocationSize(value.`headers`) + + FfiConverterByteArray.allocationSize(value.`body`) + ) - override fun write(value: Remote, buf: ByteBuffer) { - buf.putLong(lower(value)) + override fun write(value: HttpResponse, buf: ByteBuffer) { + FfiConverterUShort.write(value.`status`, buf) + FfiConverterMapStringString.write(value.`headers`, buf) + FfiConverterByteArray.write(value.`body`, buf) } } -// This template implements a class for working with a Rust struct via a handle -// to the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque handle to the underlying Rust struct. -// Method calls need to read this handle from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its handle should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the handle, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the handle, but is interrupted -// before it can pass the handle over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read handle value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - /** - * A callback invoked with download progress as a bundle downloads. + * Metadata for a single entry stored in the bundle index. + * + * `offset` and `len` refer to the entry's position in the data section. + * `content_length` is the logical (uncompressed) size exposed to HTTP clients, + * which may differ from `len` if the data is stored compressed. */ -public interface RemoteOnDownload { +data class IndexEntry ( + var `offset`: kotlin.ULong + , + var `len`: kotlin.ULong + , + var `isEmpty`: kotlin.Boolean + , + var `contentType`: kotlin.String + , + var `contentLength`: kotlin.ULong + , + var `headers`: Map - fun `onDownload`(`data`: RemoteOnDownloadData) +){ + + + + companion object } /** - * A callback invoked with download progress as a bundle downloads. + * @suppress */ -open class RemoteOnDownloadImpl: Disposable, AutoCloseable, RemoteOnDownload -{ - - @Suppress("UNUSED_PARAMETER") - /** - * @suppress - */ - constructor(withHandle: UniffiWithHandle, handle: Long) { - this.handle = handle - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(handle)) - } - - /** - * @suppress - * - * This constructor can be used to instantiate a fake object. Only used for tests. Any - * attempt to actually use an object constructed this way will fail as there is no - * connected Rust object. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noHandle: NoHandle) { - this.handle = 0 - this.cleanable = null - } - - protected val handle: Long - protected val cleanable: UniffiCleaner.Cleanable? - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - override fun destroy() { - // Only allow a single call to this method. - // TODO: maybe we should log a warning if called more than once? - if (this.wasDestroyed.compareAndSet(false, true)) { - // This decrement always matches the initial count of 1 given at creation time. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } +public object FfiConverterTypeIndexEntry: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): IndexEntry { + return IndexEntry( + FfiConverterULong.read(buf), + FfiConverterULong.read(buf), + FfiConverterBoolean.read(buf), + FfiConverterString.read(buf), + FfiConverterULong.read(buf), + FfiConverterMapStringString.read(buf), + ) } - @Synchronized - override fun close() { - this.destroy() - } + override fun allocationSize(value: IndexEntry) = ( + FfiConverterULong.allocationSize(value.`offset`) + + FfiConverterULong.allocationSize(value.`len`) + + FfiConverterBoolean.allocationSize(value.`isEmpty`) + + FfiConverterString.allocationSize(value.`contentType`) + + FfiConverterULong.allocationSize(value.`contentLength`) + + FfiConverterMapStringString.allocationSize(value.`headers`) + ) - internal inline fun callWithHandle(block: (handle: Long) -> R): R { - // Check and increment the call counter, to keep the object alive. - // This needs a compare-and-set retry loop in case of concurrent updates. - do { - val c = this.callCounter.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") - } - } while (! this.callCounter.compareAndSet(c, c + 1L)) - // Now we can safely do the method call without the handle being freed concurrently. - try { - return block(this.uniffiCloneHandle()) - } finally { - // This decrement always matches the increment we performed above. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } + override fun write(value: IndexEntry, buf: ByteBuffer) { + FfiConverterULong.write(value.`offset`, buf) + FfiConverterULong.write(value.`len`, buf) + FfiConverterBoolean.write(value.`isEmpty`, buf) + FfiConverterString.write(value.`contentType`, buf) + FfiConverterULong.write(value.`contentLength`, buf) + FfiConverterMapStringString.write(value.`headers`, buf) } +} + - // Use a static inner class instead of a closure so as not to accidentally - // capture `this` as part of the cleanable's action. - private class UniffiCleanAction(private val handle: Long) : Runnable { - override fun run() { - if (handle == 0.toLong()) { - // Fake object created with `NoHandle`, don't try to free. - return; - } - uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_remoteondownload(handle, status) - } - } - } +/** + * How a bundle's index checksum is verified when its index is read. + */ +data class IndexReadOptions ( /** - * @suppress + * How the index checksum is verified. */ - fun uniffiCloneHandle(): Long { - if (handle == 0.toLong()) { - throw InternalException("uniffiCloneHandle() called on NoHandle object"); - } - return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_remoteondownload(handle, status) - } - } - - override fun `onDownload`(`data`: RemoteOnDownloadData) - = - callWithHandle { - uniffiRustCall() { _status -> - UniffiLib.uniffi_wvb_ffi_fn_method_remoteondownload_on_download( - it, - FfiConverterTypeRemoteOnDownloadData.lower(`data`),_status) -} - } - + var `checksum`: ChecksumReadOptions? = null - +){ - - - /** - * @suppress - */ companion object - } +/** + * @suppress + */ +public object FfiConverterTypeIndexReadOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): IndexReadOptions { + return IndexReadOptions( + FfiConverterOptionalTypeChecksumReadOptions.read(buf), + ) + } + override fun allocationSize(value: IndexReadOptions) = ( + FfiConverterOptionalTypeChecksumReadOptions.allocationSize(value.`checksum`) + ) -// Put the implementation in an object so we don't pollute the top-level namespace -internal object uniffiCallbackInterfaceRemoteOnDownload { - internal object `onDownload`: UniffiCallbackInterfaceRemoteOnDownloadMethod0 { - override fun callback(`uniffiHandle`: Long,`data`: RustBuffer.ByValue,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) { - val uniffiObj = FfiConverterTypeRemoteOnDownload.handleMap.get(uniffiHandle) - val makeCall = { -> - uniffiObj.`onDownload`( - FfiConverterTypeRemoteOnDownloadData.lift(`data`), - ) - } - val writeReturn = { _: Unit -> Unit } - uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn) - } + override fun write(value: IndexReadOptions, buf: ByteBuffer) { + FfiConverterOptionalTypeChecksumReadOptions.write(value.`checksum`, buf) } +} - internal object uniffiFree: UniffiCallbackInterfaceFree { - override fun callback(handle: Long) { - FfiConverterTypeRemoteOnDownload.handleMap.remove(handle) - } - } - internal object uniffiClone: UniffiCallbackInterfaceClone { - override fun callback(handle: Long): Long { - return FfiConverterTypeRemoteOnDownload.handleMap.clone(handle) - } - } - internal var vtable = UniffiVTableCallbackInterfaceRemoteOnDownload.UniffiByValue( - uniffiFree, - uniffiClone, - `onDownload`, - ) +data class ManifestBundleItem ( + var `name`: kotlin.String + , + var `version`: kotlin.String + , + var `status`: ManifestBundleItemStatus + , + var `data`: ManifestVersionData + +){ + - // Registers the foreign callback with the Rust side. - // This method is generated for each callback interface. - internal fun register(lib: UniffiLib) { - lib.uniffi_wvb_ffi_fn_init_callback_vtable_remoteondownload(vtable) - } + + + + companion object } /** * @suppress */ -public object FfiConverterTypeRemoteOnDownload: FfiConverter { - internal val handleMap = UniffiHandleMap() - - override fun lower(value: RemoteOnDownload): Long { - if (value is RemoteOnDownloadImpl) { - // Rust-implemented object. Clone the handle and return it - return value.uniffiCloneHandle() - } else { - // Kotlin object, generate a new vtable handle and return that. - return handleMap.insert(value) - } +public object FfiConverterTypeManifestBundleItem: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ManifestBundleItem { + return ManifestBundleItem( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterTypeManifestBundleItemStatus.read(buf), + FfiConverterTypeManifestVersionData.read(buf), + ) } - override fun lift(value: Long): RemoteOnDownload { - if ((value and 1.toLong()) == 0.toLong()) { - // Rust-generated handle, construct a new class that uses the handle to implement the - // interface - return RemoteOnDownloadImpl(UniffiWithHandle, value) - } else { - // Kotlin-generated handle, get the object from the handle map - return handleMap.remove(value) - } - } + override fun allocationSize(value: ManifestBundleItem) = ( + FfiConverterString.allocationSize(value.`name`) + + FfiConverterString.allocationSize(value.`version`) + + FfiConverterTypeManifestBundleItemStatus.allocationSize(value.`status`) + + FfiConverterTypeManifestVersionData.allocationSize(value.`data`) + ) - override fun read(buf: ByteBuffer): RemoteOnDownload { - return lift(buf.getLong()) + override fun write(value: ManifestBundleItem, buf: ByteBuffer) { + FfiConverterString.write(value.`name`, buf) + FfiConverterString.write(value.`version`, buf) + FfiConverterTypeManifestBundleItemStatus.write(value.`status`, buf) + FfiConverterTypeManifestVersionData.write(value.`data`, buf) } +} - override fun allocationSize(value: RemoteOnDownload) = 8UL - override fun write(value: RemoteOnDownload, buf: ByteBuffer) { - buf.putLong(lower(value)) - } + +data class ManifestPruneResult ( + var `name`: kotlin.String + , + var `prunedVersions`: List + +){ + + + + + + companion object } +/** + * @suppress + */ +public object FfiConverterTypeManifestPruneResult: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ManifestPruneResult { + return ManifestPruneResult( + FfiConverterString.read(buf), + FfiConverterSequenceString.read(buf), + ) + } -// This template implements a class for working with a Rust struct via a handle -// to the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque handle to the underlying Rust struct. -// Method calls need to read this handle from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its handle should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the handle, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the handle, but is interrupted -// before it can pass the handle over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read handle value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// + override fun allocationSize(value: ManifestPruneResult) = ( + FfiConverterString.allocationSize(value.`name`) + + FfiConverterSequenceString.allocationSize(value.`prunedVersions`) + ) + + override fun write(value: ManifestPruneResult, buf: ByteBuffer) { + FfiConverterString.write(value.`name`, buf) + FfiConverterSequenceString.write(value.`prunedVersions`, buf) + } +} + + + +data class ManifestRemoveData ( + var `versions`: List + , + var `force`: kotlin.Boolean? = null + +){ + + + + + companion object +} /** - * A custom function that verifies a bundle's signature. + * @suppress */ -public interface SignatureVerify { +public object FfiConverterTypeManifestRemoveData: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ManifestRemoveData { + return ManifestRemoveData( + FfiConverterSequenceString.read(buf), + FfiConverterOptionalBoolean.read(buf), + ) + } + + override fun allocationSize(value: ManifestRemoveData) = ( + FfiConverterSequenceString.allocationSize(value.`versions`) + + FfiConverterOptionalBoolean.allocationSize(value.`force`) + ) + + override fun write(value: ManifestRemoveData, buf: ByteBuffer) { + FfiConverterSequenceString.write(value.`versions`, buf) + FfiConverterOptionalBoolean.write(value.`force`, buf) + } +} + + + +data class ManifestRemoveResult ( + var `name`: kotlin.String + , + var `version`: kotlin.String + , + var `kind`: ManifestRemoveResultKind - suspend fun `verify`(`message`: kotlin.ByteArray, `signature`: kotlin.String): kotlin.Boolean +){ + + + + companion object } /** - * A custom function that verifies a bundle's signature. + * @suppress */ -open class SignatureVerifyImpl: Disposable, AutoCloseable, SignatureVerify -{ - - @Suppress("UNUSED_PARAMETER") - /** - * @suppress - */ - constructor(withHandle: UniffiWithHandle, handle: Long) { - this.handle = handle - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(handle)) +public object FfiConverterTypeManifestRemoveResult: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ManifestRemoveResult { + return ManifestRemoveResult( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterTypeManifestRemoveResultKind.read(buf), + ) } - /** - * @suppress - * - * This constructor can be used to instantiate a fake object. Only used for tests. Any - * attempt to actually use an object constructed this way will fail as there is no - * connected Rust object. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noHandle: NoHandle) { - this.handle = 0 - this.cleanable = null + override fun allocationSize(value: ManifestRemoveResult) = ( + FfiConverterString.allocationSize(value.`name`) + + FfiConverterString.allocationSize(value.`version`) + + FfiConverterTypeManifestRemoveResultKind.allocationSize(value.`kind`) + ) + + override fun write(value: ManifestRemoveResult, buf: ByteBuffer) { + FfiConverterString.write(value.`name`, buf) + FfiConverterString.write(value.`version`, buf) + FfiConverterTypeManifestRemoveResultKind.write(value.`kind`, buf) } +} - protected val handle: Long - protected val cleanable: UniffiCleaner.Cleanable? - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - override fun destroy() { - // Only allow a single call to this method. - // TODO: maybe we should log a warning if called more than once? - if (this.wasDestroyed.compareAndSet(false, true)) { - // This decrement always matches the initial count of 1 given at creation time. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } +data class ManifestSetCurrentVersionResult ( + var `name`: kotlin.String + , + var `version`: kotlin.String + , + var `kind`: ManifestSetCurrentVersionResultKind + +){ + + + + + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeManifestSetCurrentVersionResult: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ManifestSetCurrentVersionResult { + return ManifestSetCurrentVersionResult( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterTypeManifestSetCurrentVersionResultKind.read(buf), + ) } - @Synchronized - override fun close() { - this.destroy() + override fun allocationSize(value: ManifestSetCurrentVersionResult) = ( + FfiConverterString.allocationSize(value.`name`) + + FfiConverterString.allocationSize(value.`version`) + + FfiConverterTypeManifestSetCurrentVersionResultKind.allocationSize(value.`kind`) + ) + + override fun write(value: ManifestSetCurrentVersionResult, buf: ByteBuffer) { + FfiConverterString.write(value.`name`, buf) + FfiConverterString.write(value.`version`, buf) + FfiConverterTypeManifestSetCurrentVersionResultKind.write(value.`kind`, buf) } +} - internal inline fun callWithHandle(block: (handle: Long) -> R): R { - // Check and increment the call counter, to keep the object alive. - // This needs a compare-and-set retry loop in case of concurrent updates. - do { - val c = this.callCounter.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") - } - } while (! this.callCounter.compareAndSet(c, c + 1L)) - // Now we can safely do the method call without the handle being freed concurrently. - try { - return block(this.uniffiCloneHandle()) - } finally { - // This decrement always matches the increment we performed above. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } + + +data class ManifestStageData ( + var `version`: kotlin.String + , + var `data`: ManifestVersionData? + +){ + + + + + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeManifestStageData: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ManifestStageData { + return ManifestStageData( + FfiConverterString.read(buf), + FfiConverterOptionalTypeManifestVersionData.read(buf), + ) } - // Use a static inner class instead of a closure so as not to accidentally - // capture `this` as part of the cleanable's action. - private class UniffiCleanAction(private val handle: Long) : Runnable { - override fun run() { - if (handle == 0.toLong()) { - // Fake object created with `NoHandle`, don't try to free. - return; - } - uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_signatureverify(handle, status) - } - } + override fun allocationSize(value: ManifestStageData) = ( + FfiConverterString.allocationSize(value.`version`) + + FfiConverterOptionalTypeManifestVersionData.allocationSize(value.`data`) + ) + + override fun write(value: ManifestStageData, buf: ByteBuffer) { + FfiConverterString.write(value.`version`, buf) + FfiConverterOptionalTypeManifestVersionData.write(value.`data`, buf) } +} - /** - * @suppress - */ - fun uniffiCloneHandle(): Long { - if (handle == 0.toLong()) { - throw InternalException("uniffiCloneHandle() called on NoHandle object"); - } - return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_signatureverify(handle, status) - } + + +data class ManifestStageResult ( + var `name`: kotlin.String + , + var `version`: kotlin.String + , + var `kind`: ManifestStageResultKind + +){ + + + + + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeManifestStageResult: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ManifestStageResult { + return ManifestStageResult( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterTypeManifestStageResultKind.read(buf), + ) + } + + override fun allocationSize(value: ManifestStageResult) = ( + FfiConverterString.allocationSize(value.`name`) + + FfiConverterString.allocationSize(value.`version`) + + FfiConverterTypeManifestStageResultKind.allocationSize(value.`kind`) + ) + + override fun write(value: ManifestStageResult, buf: ByteBuffer) { + FfiConverterString.write(value.`name`, buf) + FfiConverterString.write(value.`version`, buf) + FfiConverterTypeManifestStageResultKind.write(value.`kind`, buf) } +} + + +data class ManifestVersionData ( + var `integrity`: kotlin.String? + , + var `metadata`: Map? - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `verify`(`message`: kotlin.ByteArray, `signature`: kotlin.String) : kotlin.Boolean { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_signatureverify_verify( - uniffiHandle, - FfiConverterByteArray.lower(`message`),FfiConverterString.lower(`signature`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_i8(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_i8(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_i8(future) }, - // lift function - { FfiConverterBoolean.lift(it) }, - // Error FFI converter - UniffiNullRustCallStatusErrorHandler, +){ + + + + + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeManifestVersionData: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ManifestVersionData { + return ManifestVersionData( + FfiConverterOptionalString.read(buf), + FfiConverterOptionalMapStringString.read(buf), + ) + } + + override fun allocationSize(value: ManifestVersionData) = ( + FfiConverterOptionalString.allocationSize(value.`integrity`) + + FfiConverterOptionalMapStringString.allocationSize(value.`metadata`) ) + + override fun write(value: ManifestVersionData, buf: ByteBuffer) { + FfiConverterOptionalString.write(value.`integrity`, buf) + FfiConverterOptionalMapStringString.write(value.`metadata`, buf) } +} + + +/** + * Options used to request the current update document. + */ +data class RemoteGetUpdateOptions ( + /** + * Entity tag of the previously received update document. + */ + var `etag`: kotlin.String? = null + , + /** + * Release channel to request. + */ + var `channel`: kotlin.String? = null + , + /** + * Public key that must sign the response. + */ + var `expectSignature`: SignatureVerifyKey? = null - +): Disposable{ + + @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here + override fun destroy() { + + Disposable.destroy( + this.`etag`, + this.`channel`, + this.`expectSignature` + ) + } - /** - * @suppress - */ companion object - } +/** + * @suppress + */ +public object FfiConverterTypeRemoteGetUpdateOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RemoteGetUpdateOptions { + return RemoteGetUpdateOptions( + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalTypeSignatureVerifyKey.read(buf), + ) + } + override fun allocationSize(value: RemoteGetUpdateOptions) = ( + FfiConverterOptionalString.allocationSize(value.`etag`) + + FfiConverterOptionalString.allocationSize(value.`channel`) + + FfiConverterOptionalTypeSignatureVerifyKey.allocationSize(value.`expectSignature`) + ) -// Put the implementation in an object so we don't pollute the top-level namespace -internal object uniffiCallbackInterfaceSignatureVerify { - internal object `verify`: UniffiCallbackInterfaceSignatureVerifyMethod0 { - override fun callback(`uniffiHandle`: Long,`message`: RustBuffer.ByValue,`signature`: RustBuffer.ByValue,`uniffiFutureCallback`: UniffiForeignFutureCompleteI8,`uniffiCallbackData`: Long,`uniffiOutDroppedCallback`: UniffiForeignFutureDroppedCallbackStruct,) { - val uniffiObj = FfiConverterTypeSignatureVerify.handleMap.get(uniffiHandle) - val makeCall = suspend { -> - uniffiObj.`verify`( - FfiConverterByteArray.lift(`message`), - FfiConverterString.lift(`signature`), - ) - } - val uniffiHandleSuccess = { returnValue: kotlin.Boolean -> - val uniffiResult = UniffiForeignFutureResultI8.UniffiByValue( - FfiConverterBoolean.lower(returnValue), - UniffiRustCallStatus.ByValue() - ) - uniffiResult.write() - uniffiFutureCallback.callback(uniffiCallbackData, uniffiResult) - } - val uniffiHandleError = { callStatus: UniffiRustCallStatus.ByValue -> - uniffiFutureCallback.callback( - uniffiCallbackData, - UniffiForeignFutureResultI8.UniffiByValue( - 0.toByte(), - callStatus, - ), - ) - } - uniffiTraitInterfaceCallAsync( - makeCall, - uniffiHandleSuccess, - uniffiHandleError, - uniffiOutDroppedCallback - ) - } + override fun write(value: RemoteGetUpdateOptions, buf: ByteBuffer) { + FfiConverterOptionalString.write(value.`etag`, buf) + FfiConverterOptionalString.write(value.`channel`, buf) + FfiConverterOptionalTypeSignatureVerifyKey.write(value.`expectSignature`, buf) } +} - internal object uniffiFree: UniffiCallbackInterfaceFree { - override fun callback(handle: Long) { - FfiConverterTypeSignatureVerify.handleMap.remove(handle) - } - } - internal object uniffiClone: UniffiCallbackInterfaceClone { - override fun callback(handle: Long): Long { - return FfiConverterTypeSignatureVerify.handleMap.clone(handle) - } - } - internal var vtable = UniffiVTableCallbackInterfaceSignatureVerify.UniffiByValue( - uniffiFree, - uniffiClone, - `verify`, - ) +/** + * Progress reported while a bundle is downloading. + */ +data class RemoteOnDownloadData ( + /** + * Bytes downloaded so far. + */ + var `downloadedBytes`: kotlin.ULong + , + /** + * Total bytes to download, when the server advertised a content length. + */ + var `totalBytes`: kotlin.ULong? + , + /** + * The endpoint the bundle is being downloaded from. + */ + var `url`: kotlin.String + +){ + - // Registers the foreign callback with the Rust side. - // This method is generated for each callback interface. - internal fun register(lib: UniffiLib) { - lib.uniffi_wvb_ffi_fn_init_callback_vtable_signatureverify(vtable) - } + + + + companion object } /** * @suppress */ -public object FfiConverterTypeSignatureVerify: FfiConverter { - internal val handleMap = UniffiHandleMap() - - override fun lower(value: SignatureVerify): Long { - if (value is SignatureVerifyImpl) { - // Rust-implemented object. Clone the handle and return it - return value.uniffiCloneHandle() - } else { - // Kotlin object, generate a new vtable handle and return that. - return handleMap.insert(value) - } +public object FfiConverterTypeRemoteOnDownloadData: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RemoteOnDownloadData { + return RemoteOnDownloadData( + FfiConverterULong.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterString.read(buf), + ) } - override fun lift(value: Long): SignatureVerify { - if ((value and 1.toLong()) == 0.toLong()) { - // Rust-generated handle, construct a new class that uses the handle to implement the - // interface - return SignatureVerifyImpl(UniffiWithHandle, value) - } else { - // Kotlin-generated handle, get the object from the handle map - return handleMap.remove(value) - } - } + override fun allocationSize(value: RemoteOnDownloadData) = ( + FfiConverterULong.allocationSize(value.`downloadedBytes`) + + FfiConverterOptionalULong.allocationSize(value.`totalBytes`) + + FfiConverterString.allocationSize(value.`url`) + ) - override fun read(buf: ByteBuffer): SignatureVerify { - return lift(buf.getLong()) + override fun write(value: RemoteOnDownloadData, buf: ByteBuffer) { + FfiConverterULong.write(value.`downloadedBytes`, buf) + FfiConverterOptionalULong.write(value.`totalBytes`, buf) + FfiConverterString.write(value.`url`, buf) } +} - override fun allocationSize(value: SignatureVerify) = 8UL - override fun write(value: SignatureVerify, buf: ByteBuffer) { - buf.putLong(lower(value)) - } -} +/** + * Options for creating a [`Remote`] client. + */ +data class RemoteOptions ( + /** + * HTTP client options. + */ + var `http`: HttpOptions? = null + , + /** + * Download progress callback. + */ + var `onDownload`: RemoteOnDownload? = null + +): Disposable{ + + + + + + @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here + override fun destroy() { + + Disposable.destroy( + this.`http`, + this.`onDownload` + ) + } + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeRemoteOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RemoteOptions { + return RemoteOptions( + FfiConverterOptionalTypeHttpOptions.read(buf), + FfiConverterOptionalTypeRemoteOnDownload.read(buf), + ) + } + + override fun allocationSize(value: RemoteOptions) = ( + FfiConverterOptionalTypeHttpOptions.allocationSize(value.`http`) + + FfiConverterOptionalTypeRemoteOnDownload.allocationSize(value.`onDownload`) + ) + + override fun write(value: RemoteOptions, buf: ByteBuffer) { + FfiConverterOptionalTypeHttpOptions.write(value.`http`, buf) + FfiConverterOptionalTypeRemoteOnDownload.write(value.`onDownload`, buf) + } +} -// This template implements a class for working with a Rust struct via a handle -// to the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque handle to the underlying Rust struct. -// Method calls need to read this handle from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its handle should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the handle, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the handle, but is interrupted -// before it can pass the handle over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read handle value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// /** - * Orchestrates the full update cycle: checks for a new version on the remote, - * downloads it, verifies integrity/signature, and writes it to the local source. + * A successful response from [`Remote::get_update`]. */ -public interface UpdaterInterface { - +data class RemoteUpdateResponse ( /** - * Downloads and persists an update for `bundle_name`. - * Uses the latest remote version when `version` is `None`. + * Parsed update document. */ - suspend fun `downloadUpdate`(`bundleName`: kotlin.String, `version`: kotlin.String?): RemoteBundleInfo - + var `update`: Update + , /** - * Checks whether a newer version of `bundle_name` is available on the remote. - * Does not download the bundle. + * HTTP entity tag supplied by the remote server. */ - suspend fun `getUpdate`(`bundleName`: kotlin.String): BundleUpdateInfo - + var `etag`: kotlin.String? + , /** - * Activates a previously downloaded bundle version. - * - * The version must already be staged in the remote source (via - * [`download_update`](Updater::download_update)). When integrity/signature - * verification is configured, the staged bundle is verified before activation. - * On success the current version is updated, the cached descriptor is dropped, - * and stale staged versions are pruned. + * Signature metadata supplied by the remote server. */ - suspend fun `install`(`bundleName`: kotlin.String, `version`: kotlin.String) + var `signature`: UpdateSignature? + +){ + + - suspend fun `listRemotes`(): List + companion object } /** - * Orchestrates the full update cycle: checks for a new version on the remote, - * downloads it, verifies integrity/signature, and writes it to the local source. + * @suppress */ -open class Updater: Disposable, AutoCloseable, UpdaterInterface -{ - - @Suppress("UNUSED_PARAMETER") - /** - * @suppress - */ - constructor(withHandle: UniffiWithHandle, handle: Long) { - this.handle = handle - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(handle)) +public object FfiConverterTypeRemoteUpdateResponse: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RemoteUpdateResponse { + return RemoteUpdateResponse( + FfiConverterTypeUpdate.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalTypeUpdateSignature.read(buf), + ) } - /** - * @suppress - * - * This constructor can be used to instantiate a fake object. Only used for tests. Any - * attempt to actually use an object constructed this way will fail as there is no - * connected Rust object. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noHandle: NoHandle) { - this.handle = 0 - this.cleanable = null + override fun allocationSize(value: RemoteUpdateResponse) = ( + FfiConverterTypeUpdate.allocationSize(value.`update`) + + FfiConverterOptionalString.allocationSize(value.`etag`) + + FfiConverterOptionalTypeUpdateSignature.allocationSize(value.`signature`) + ) + + override fun write(value: RemoteUpdateResponse, buf: ByteBuffer) { + FfiConverterTypeUpdate.write(value.`update`, buf) + FfiConverterOptionalString.write(value.`etag`, buf) + FfiConverterOptionalTypeUpdateSignature.write(value.`signature`, buf) } - constructor(`source`: BundleSource, `remote`: Remote, `options`: UpdaterOptions?) : - this(UniffiWithHandle, - uniffiRustCallWithError(WebviewBundleException) { _status -> - UniffiLib.uniffi_wvb_ffi_fn_constructor_updater_new( - - FfiConverterTypeBundleSource.lower(`source`),FfiConverterTypeRemote.lower(`remote`),FfiConverterOptionalTypeUpdaterOptions.lower(`options`),_status) } - ) - protected val handle: Long - protected val cleanable: UniffiCleaner.Cleanable? - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) +data class SignatureVerifyKey ( + var `id`: kotlin.String? + , + var `verify`: SignatureVerify + +): Disposable{ + + + + + + @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here override fun destroy() { - // Only allow a single call to this method. - // TODO: maybe we should log a warning if called more than once? - if (this.wasDestroyed.compareAndSet(false, true)) { - // This decrement always matches the initial count of 1 given at creation time. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } + + Disposable.destroy( + this.`id`, + this.`verify` + ) } + + companion object +} - @Synchronized - override fun close() { - this.destroy() +/** + * @suppress + */ +public object FfiConverterTypeSignatureVerifyKey: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): SignatureVerifyKey { + return SignatureVerifyKey( + FfiConverterOptionalString.read(buf), + FfiConverterTypeSignatureVerify.read(buf), + ) } - internal inline fun callWithHandle(block: (handle: Long) -> R): R { - // Check and increment the call counter, to keep the object alive. - // This needs a compare-and-set retry loop in case of concurrent updates. - do { - val c = this.callCounter.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") - } - } while (! this.callCounter.compareAndSet(c, c + 1L)) - // Now we can safely do the method call without the handle being freed concurrently. - try { - return block(this.uniffiCloneHandle()) - } finally { - // This decrement always matches the increment we performed above. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable?.clean() - } - } - } + override fun allocationSize(value: SignatureVerifyKey) = ( + FfiConverterOptionalString.allocationSize(value.`id`) + + FfiConverterTypeSignatureVerify.allocationSize(value.`verify`) + ) - // Use a static inner class instead of a closure so as not to accidentally - // capture `this` as part of the cleanable's action. - private class UniffiCleanAction(private val handle: Long) : Runnable { - override fun run() { - if (handle == 0.toLong()) { - // Fake object created with `NoHandle`, don't try to free. - return; - } - uniffiRustCall { status -> - UniffiLib.uniffi_wvb_ffi_fn_free_updater(handle, status) - } - } + override fun write(value: SignatureVerifyKey, buf: ByteBuffer) { + FfiConverterOptionalString.write(value.`id`, buf) + FfiConverterTypeSignatureVerify.write(value.`verify`, buf) } +} + + +data class SourceConfig ( + var `builtinDir`: kotlin.String + , + var `remoteDir`: kotlin.String + , + var `builtinManifestFilepath`: kotlin.String? = null + , + var `remoteManifestFilepath`: kotlin.String? = null + , /** - * @suppress + * How bundles are checked against their manifest integrity metadata on load. */ - fun uniffiCloneHandle(): Long { - if (handle == 0.toLong()) { - throw InternalException("uniffiCloneHandle() called on NoHandle object"); - } - return uniffiRustCall() { status -> - UniffiLib.uniffi_wvb_ffi_fn_clone_updater(handle, status) - } - } - - + var `integrity`: SourceIntegrityOptions? = null + , /** - * Downloads and persists an update for `bundle_name`. - * Uses the latest remote version when `version` is `None`. + * How each entry's checksum is verified when its data is read. */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `downloadUpdate`(`bundleName`: kotlin.String, `version`: kotlin.String?) : RemoteBundleInfo { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_updater_download_update( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterOptionalString.lower(`version`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterTypeRemoteBundleInfo.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) - } - - + var `dataReadOptions`: DataReadOptions? = null + , /** - * Checks whether a newer version of `bundle_name` is available on the remote. - * Does not download the bundle. + * How a bundle's header checksum is verified when its descriptor is read on load. */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `getUpdate`(`bundleName`: kotlin.String) : BundleUpdateInfo { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_updater_get_update( - uniffiHandle, - FfiConverterString.lower(`bundleName`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterTypeBundleUpdateInfo.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, + var `headerReadOptions`: HeaderReadOptions? = null + , + /** + * How a bundle's index checksum is verified when its descriptor is read on load. + */ + var `indexReadOptions`: IndexReadOptions? = null + , + var `removeBundleChunkSize`: kotlin.UInt? = null + +){ + + + + + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeSourceConfig: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): SourceConfig { + return SourceConfig( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalTypeSourceIntegrityOptions.read(buf), + FfiConverterOptionalTypeDataReadOptions.read(buf), + FfiConverterOptionalTypeHeaderReadOptions.read(buf), + FfiConverterOptionalTypeIndexReadOptions.read(buf), + FfiConverterOptionalUInt.read(buf), + ) + } + + override fun allocationSize(value: SourceConfig) = ( + FfiConverterString.allocationSize(value.`builtinDir`) + + FfiConverterString.allocationSize(value.`remoteDir`) + + FfiConverterOptionalString.allocationSize(value.`builtinManifestFilepath`) + + FfiConverterOptionalString.allocationSize(value.`remoteManifestFilepath`) + + FfiConverterOptionalTypeSourceIntegrityOptions.allocationSize(value.`integrity`) + + FfiConverterOptionalTypeDataReadOptions.allocationSize(value.`dataReadOptions`) + + FfiConverterOptionalTypeHeaderReadOptions.allocationSize(value.`headerReadOptions`) + + FfiConverterOptionalTypeIndexReadOptions.allocationSize(value.`indexReadOptions`) + + FfiConverterOptionalUInt.allocationSize(value.`removeBundleChunkSize`) ) + + override fun write(value: SourceConfig, buf: ByteBuffer) { + FfiConverterString.write(value.`builtinDir`, buf) + FfiConverterString.write(value.`remoteDir`, buf) + FfiConverterOptionalString.write(value.`builtinManifestFilepath`, buf) + FfiConverterOptionalString.write(value.`remoteManifestFilepath`, buf) + FfiConverterOptionalTypeSourceIntegrityOptions.write(value.`integrity`, buf) + FfiConverterOptionalTypeDataReadOptions.write(value.`dataReadOptions`, buf) + FfiConverterOptionalTypeHeaderReadOptions.write(value.`headerReadOptions`, buf) + FfiConverterOptionalTypeIndexReadOptions.write(value.`indexReadOptions`, buf) + FfiConverterOptionalUInt.write(value.`removeBundleChunkSize`, buf) } +} - + + +/** + * How bundles are checked against the integrity recorded for them in the manifest when + * they are loaded from disk. + */ +data class SourceIntegrityOptions ( /** - * Activates a previously downloaded bundle version. + * How a bundle's integrity metadata is treated (default: [`IntegrityPolicy::Optional`]). * - * The version must already be staged in the remote source (via - * [`download_update`](Updater::download_update)). When integrity/signature - * verification is configured, the staged bundle is verified before activation. - * On success the current version is updated, the cached descriptor is dropped, - * and stale staged versions are pruned. + * [`IntegrityPolicy::Off`] disables the integrity check entirely. */ - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `install`(`bundleName`: kotlin.String, `version`: kotlin.String) { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_updater_install( - uniffiHandle, - FfiConverterString.lower(`bundleName`),FfiConverterString.lower(`version`), - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_void(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_void(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_void(future) }, - // lift function - { Unit }, - - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) - } - + var `policy`: IntegrityPolicy? = null + , + var `checkMode`: SourceIntegrityCheckMode? = null - @Throws(WebviewBundleException::class) - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - override suspend fun `listRemotes`() : List { - return uniffiRustCallAsync( - callWithHandle { uniffiHandle -> - UniffiLib.uniffi_wvb_ffi_fn_method_updater_list_remotes( - uniffiHandle, - - ) - }, - { future, callback, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_poll_rust_buffer(future, callback, continuation) }, - { future, continuation -> UniffiLib.ffi_wvb_ffi_rust_future_complete_rust_buffer(future, continuation) }, - { future -> UniffiLib.ffi_wvb_ffi_rust_future_free_rust_buffer(future) }, - // lift function - { FfiConverterSequenceTypeListRemoteBundleInfo.lift(it) }, - // Error FFI converter - WebviewBundleException.ErrorHandler, - ) - } - +){ - - - /** - * @suppress - */ companion object - } - /** * @suppress */ -public object FfiConverterTypeUpdater: FfiConverter { - override fun lower(value: Updater): Long { - return value.uniffiCloneHandle() +public object FfiConverterTypeSourceIntegrityOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): SourceIntegrityOptions { + return SourceIntegrityOptions( + FfiConverterOptionalTypeIntegrityPolicy.read(buf), + FfiConverterOptionalTypeSourceIntegrityCheckMode.read(buf), + ) } - override fun lift(value: Long): Updater { - return Updater(UniffiWithHandle, value) + override fun allocationSize(value: SourceIntegrityOptions) = ( + FfiConverterOptionalTypeIntegrityPolicy.allocationSize(value.`policy`) + + FfiConverterOptionalTypeSourceIntegrityCheckMode.allocationSize(value.`checkMode`) + ) + + override fun write(value: SourceIntegrityOptions, buf: ByteBuffer) { + FfiConverterOptionalTypeIntegrityPolicy.write(value.`policy`, buf) + FfiConverterOptionalTypeSourceIntegrityCheckMode.write(value.`checkMode`, buf) } +} - override fun read(buf: ByteBuffer): Updater { - return lift(buf.getLong()) + + +data class SourceListItem ( + var `source`: SourceKind + , + var `item`: ManifestBundleItem + +){ + + + + + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeSourceListItem: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): SourceListItem { + return SourceListItem( + FfiConverterTypeSourceKind.read(buf), + FfiConverterTypeManifestBundleItem.read(buf), + ) } - override fun allocationSize(value: Updater) = 8UL + override fun allocationSize(value: SourceListItem) = ( + FfiConverterTypeSourceKind.allocationSize(value.`source`) + + FfiConverterTypeManifestBundleItem.allocationSize(value.`item`) + ) - override fun write(value: Updater, buf: ByteBuffer) { - buf.putLong(lower(value)) + override fun write(value: SourceListItem, buf: ByteBuffer) { + FfiConverterTypeSourceKind.write(value.`source`, buf) + FfiConverterTypeManifestBundleItem.write(value.`item`, buf) } } /** - * Options for the bundle header section. + * An atomically published set of bundle updates. */ -data class BuildHeaderOptions ( - var `checksum`: ChecksumWriteOptions? = null +data class Update ( + /** + * Unique update identifier. + */ + var `id`: kotlin.String + , + /** + * ISO 8601 publication time. + */ + var `createdAt`: kotlin.String + , + /** + * Update-model version required to process this document. + */ + var `runtimeVersion`: kotlin.UByte + , + /** + * Bundles included in this update. + */ + var `bundles`: List + , + /** + * Provider-defined, string-valued update metadata. + */ + var `metadata`: Map? ){ @@ -7798,29 +9329,54 @@ data class BuildHeaderOptions ( /** * @suppress */ -public object FfiConverterTypeBuildHeaderOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BuildHeaderOptions { - return BuildHeaderOptions( - FfiConverterOptionalTypeChecksumWriteOptions.read(buf), +public object FfiConverterTypeUpdate: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Update { + return Update( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterUByte.read(buf), + FfiConverterSequenceTypeBundleUpdate.read(buf), + FfiConverterOptionalMapStringString.read(buf), ) } - override fun allocationSize(value: BuildHeaderOptions) = ( - FfiConverterOptionalTypeChecksumWriteOptions.allocationSize(value.`checksum`) + override fun allocationSize(value: Update) = ( + FfiConverterString.allocationSize(value.`id`) + + FfiConverterString.allocationSize(value.`createdAt`) + + FfiConverterUByte.allocationSize(value.`runtimeVersion`) + + FfiConverterSequenceTypeBundleUpdate.allocationSize(value.`bundles`) + + FfiConverterOptionalMapStringString.allocationSize(value.`metadata`) ) - override fun write(value: BuildHeaderOptions, buf: ByteBuffer) { - FfiConverterOptionalTypeChecksumWriteOptions.write(value.`checksum`, buf) + override fun write(value: Update, buf: ByteBuffer) { + FfiConverterString.write(value.`id`, buf) + FfiConverterString.write(value.`createdAt`, buf) + FfiConverterUByte.write(value.`runtimeVersion`, buf) + FfiConverterSequenceTypeBundleUpdate.write(value.`bundles`, buf) + FfiConverterOptionalMapStringString.write(value.`metadata`, buf) } } /** - * Pptions for the bundle index section. + * Signature metadata returned with an update document. */ -data class BuildIndexOptions ( - var `checksum`: ChecksumWriteOptions? = null +data class UpdateSignature ( + /** + * Identifier of the public key used to verify the signature. + */ + var `keyId`: kotlin.String + , + /** + * Base64-encoded signature of the raw update document. + */ + var `sig`: kotlin.String + , + /** + * Signature algorithm used for [`Self::sig`]. + */ + var `alg`: kotlin.String ){ @@ -7834,83 +9390,93 @@ data class BuildIndexOptions ( /** * @suppress */ -public object FfiConverterTypeBuildIndexOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BuildIndexOptions { - return BuildIndexOptions( - FfiConverterOptionalTypeChecksumWriteOptions.read(buf), +public object FfiConverterTypeUpdateSignature: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdateSignature { + return UpdateSignature( + FfiConverterString.read(buf), + FfiConverterString.read(buf), + FfiConverterString.read(buf), ) } - override fun allocationSize(value: BuildIndexOptions) = ( - FfiConverterOptionalTypeChecksumWriteOptions.allocationSize(value.`checksum`) + override fun allocationSize(value: UpdateSignature) = ( + FfiConverterString.allocationSize(value.`keyId`) + + FfiConverterString.allocationSize(value.`sig`) + + FfiConverterString.allocationSize(value.`alg`) ) - override fun write(value: BuildIndexOptions, buf: ByteBuffer) { - FfiConverterOptionalTypeChecksumWriteOptions.write(value.`checksum`, buf) + override fun write(value: UpdateSignature, buf: ByteBuffer) { + FfiConverterString.write(value.`keyId`, buf) + FfiConverterString.write(value.`sig`, buf) + FfiConverterString.write(value.`alg`, buf) } } -/** - * Top-level options passed to [`BundleBuilder::build`]. - * All fields are optional; omitting them applies the library defaults. - */ -data class BuildOptions ( - var `header`: BuildHeaderOptions? +data class UpdaterDownloadOptions ( + var `concurrency`: kotlin.UInt? = null , - var `index`: BuildIndexOptions? + var `timeout`: kotlin.ULong? = null , - var `dataChecksum`: ChecksumWriteOptions? + var `cancellation`: Cancellation? = null -){ +): Disposable{ + @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here + override fun destroy() { + + Disposable.destroy( + this.`concurrency`, + this.`timeout`, + this.`cancellation` + ) + } + companion object } /** * @suppress */ -public object FfiConverterTypeBuildOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BuildOptions { - return BuildOptions( - FfiConverterOptionalTypeBuildHeaderOptions.read(buf), - FfiConverterOptionalTypeBuildIndexOptions.read(buf), - FfiConverterOptionalTypeChecksumWriteOptions.read(buf), +public object FfiConverterTypeUpdaterDownloadOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterDownloadOptions { + return UpdaterDownloadOptions( + FfiConverterOptionalUInt.read(buf), + FfiConverterOptionalULong.read(buf), + FfiConverterOptionalTypeCancellation.read(buf), ) } - override fun allocationSize(value: BuildOptions) = ( - FfiConverterOptionalTypeBuildHeaderOptions.allocationSize(value.`header`) + - FfiConverterOptionalTypeBuildIndexOptions.allocationSize(value.`index`) + - FfiConverterOptionalTypeChecksumWriteOptions.allocationSize(value.`dataChecksum`) + override fun allocationSize(value: UpdaterDownloadOptions) = ( + FfiConverterOptionalUInt.allocationSize(value.`concurrency`) + + FfiConverterOptionalULong.allocationSize(value.`timeout`) + + FfiConverterOptionalTypeCancellation.allocationSize(value.`cancellation`) ) - override fun write(value: BuildOptions, buf: ByteBuffer) { - FfiConverterOptionalTypeBuildHeaderOptions.write(value.`header`, buf) - FfiConverterOptionalTypeBuildIndexOptions.write(value.`index`, buf) - FfiConverterOptionalTypeChecksumWriteOptions.write(value.`dataChecksum`, buf) + override fun write(value: UpdaterDownloadOptions, buf: ByteBuffer) { + FfiConverterOptionalUInt.write(value.`concurrency`, buf) + FfiConverterOptionalULong.write(value.`timeout`, buf) + FfiConverterOptionalTypeCancellation.write(value.`cancellation`, buf) } } -/** - * HTTP cache-control fields stored alongside each bundle entry in the manifest. - * Used to avoid re-downloading bundles that haven't changed. - */ -data class BundleManifestMetadata ( - var `etag`: kotlin.String? +data class UpdaterDownloadResult ( + var `name`: kotlin.String + , + var `version`: kotlin.String , var `integrity`: kotlin.String? , - var `signature`: kotlin.String? + var `metadata`: Map? , - var `lastModified`: kotlin.String? + var `result`: UpdaterDownloadResultKind ){ @@ -7924,43 +9490,38 @@ data class BundleManifestMetadata ( /** * @suppress */ -public object FfiConverterTypeBundleManifestMetadata: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleManifestMetadata { - return BundleManifestMetadata( - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), +public object FfiConverterTypeUpdaterDownloadResult: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterDownloadResult { + return UpdaterDownloadResult( + FfiConverterString.read(buf), + FfiConverterString.read(buf), FfiConverterOptionalString.read(buf), + FfiConverterOptionalMapStringString.read(buf), + FfiConverterTypeUpdaterDownloadResultKind.read(buf), ) } - override fun allocationSize(value: BundleManifestMetadata) = ( - FfiConverterOptionalString.allocationSize(value.`etag`) + + override fun allocationSize(value: UpdaterDownloadResult) = ( + FfiConverterString.allocationSize(value.`name`) + + FfiConverterString.allocationSize(value.`version`) + FfiConverterOptionalString.allocationSize(value.`integrity`) + - FfiConverterOptionalString.allocationSize(value.`signature`) + - FfiConverterOptionalString.allocationSize(value.`lastModified`) + FfiConverterOptionalMapStringString.allocationSize(value.`metadata`) + + FfiConverterTypeUpdaterDownloadResultKind.allocationSize(value.`result`) ) - override fun write(value: BundleManifestMetadata, buf: ByteBuffer) { - FfiConverterOptionalString.write(value.`etag`, buf) + override fun write(value: UpdaterDownloadResult, buf: ByteBuffer) { + FfiConverterString.write(value.`name`, buf) + FfiConverterString.write(value.`version`, buf) FfiConverterOptionalString.write(value.`integrity`, buf) - FfiConverterOptionalString.write(value.`signature`, buf) - FfiConverterOptionalString.write(value.`lastModified`, buf) + FfiConverterOptionalMapStringString.write(value.`metadata`, buf) + FfiConverterTypeUpdaterDownloadResultKind.write(value.`result`, buf) } } -/** - * How a [`BundleProtocolHandler`] resolves the request uri. - * - * Defaults to the first hostname segment as the bundle name, and a directory-index path - * (`/about` -> `/about/index.html`). - */ -data class BundleProtocolOptions ( - var `bundleResolver`: BundleResolver? = null - , - var `pathResolver`: PathResolver? = null +data class UpdaterGetUpdateOptions ( + var `expectSignatureKeyId`: kotlin.String? = null ){ @@ -7974,136 +9535,111 @@ data class BundleProtocolOptions ( /** * @suppress */ -public object FfiConverterTypeBundleProtocolOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleProtocolOptions { - return BundleProtocolOptions( - FfiConverterOptionalTypeBundleResolver.read(buf), - FfiConverterOptionalTypePathResolver.read(buf), +public object FfiConverterTypeUpdaterGetUpdateOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterGetUpdateOptions { + return UpdaterGetUpdateOptions( + FfiConverterOptionalString.read(buf), ) } - override fun allocationSize(value: BundleProtocolOptions) = ( - FfiConverterOptionalTypeBundleResolver.allocationSize(value.`bundleResolver`) + - FfiConverterOptionalTypePathResolver.allocationSize(value.`pathResolver`) + override fun allocationSize(value: UpdaterGetUpdateOptions) = ( + FfiConverterOptionalString.allocationSize(value.`expectSignatureKeyId`) ) - override fun write(value: BundleProtocolOptions, buf: ByteBuffer) { - FfiConverterOptionalTypeBundleResolver.write(value.`bundleResolver`, buf) - FfiConverterOptionalTypePathResolver.write(value.`pathResolver`, buf) + override fun write(value: UpdaterGetUpdateOptions, buf: ByteBuffer) { + FfiConverterOptionalString.write(value.`expectSignatureKeyId`, buf) } } -data class BundleSourceConfig ( - var `builtinDir`: kotlin.String - , - var `remoteDir`: kotlin.String - , - var `builtinManifestFilepath`: kotlin.String? = null - , - var `remoteManifestFilepath`: kotlin.String? = null - , - /** - * How bundles are checked against their manifest integrity metadata on load. - */ - var `integrity`: BundleSourceIntegrityOptions? = null +data class UpdaterInstallResult ( + var `name`: kotlin.String , - /** - * How bundle signatures are verified on load. - */ - var `signature`: BundleSourceSignatureOptions? = null + var `targetVersion`: kotlin.String? , - /** - * How each entry's checksum is verified when its data is read. - */ - var `dataReadOptions`: DataReadOptions? = null + var `installVersion`: kotlin.String? , - /** - * How a bundle's header checksum is verified when its descriptor is read on load. - */ - var `headerReadOptions`: HeaderReadOptions? = null + var `result`: UpdaterInstallResultKind + +){ + + + + + + companion object +} + +/** + * @suppress + */ +public object FfiConverterTypeUpdaterInstallResult: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterInstallResult { + return UpdaterInstallResult( + FfiConverterString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterTypeUpdaterInstallResultKind.read(buf), + ) + } + + override fun allocationSize(value: UpdaterInstallResult) = ( + FfiConverterString.allocationSize(value.`name`) + + FfiConverterOptionalString.allocationSize(value.`targetVersion`) + + FfiConverterOptionalString.allocationSize(value.`installVersion`) + + FfiConverterTypeUpdaterInstallResultKind.allocationSize(value.`result`) + ) + + override fun write(value: UpdaterInstallResult, buf: ByteBuffer) { + FfiConverterString.write(value.`name`, buf) + FfiConverterOptionalString.write(value.`targetVersion`, buf) + FfiConverterOptionalString.write(value.`installVersion`, buf) + FfiConverterTypeUpdaterInstallResultKind.write(value.`result`, buf) + } +} + + + +data class UpdaterInstallTarget ( + var `name`: kotlin.String , - /** - * How a bundle's index checksum is verified when its descriptor is read on load. - */ - var `indexReadOptions`: IndexReadOptions? = null + var `version`: kotlin.String? -): Disposable{ +){ - @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here - override fun destroy() { - - Disposable.destroy( - this.`builtinDir`, - this.`remoteDir`, - this.`builtinManifestFilepath`, - this.`remoteManifestFilepath`, - this.`integrity`, - this.`signature`, - this.`dataReadOptions`, - this.`headerReadOptions`, - this.`indexReadOptions` - ) - } - companion object } /** * @suppress */ -public object FfiConverterTypeBundleSourceConfig: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleSourceConfig { - return BundleSourceConfig( +public object FfiConverterTypeUpdaterInstallTarget: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterInstallTarget { + return UpdaterInstallTarget( FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterOptionalString.read(buf), FfiConverterOptionalString.read(buf), - FfiConverterOptionalTypeBundleSourceIntegrityOptions.read(buf), - FfiConverterOptionalTypeBundleSourceSignatureOptions.read(buf), - FfiConverterOptionalTypeDataReadOptions.read(buf), - FfiConverterOptionalTypeHeaderReadOptions.read(buf), - FfiConverterOptionalTypeIndexReadOptions.read(buf), ) } - override fun allocationSize(value: BundleSourceConfig) = ( - FfiConverterString.allocationSize(value.`builtinDir`) + - FfiConverterString.allocationSize(value.`remoteDir`) + - FfiConverterOptionalString.allocationSize(value.`builtinManifestFilepath`) + - FfiConverterOptionalString.allocationSize(value.`remoteManifestFilepath`) + - FfiConverterOptionalTypeBundleSourceIntegrityOptions.allocationSize(value.`integrity`) + - FfiConverterOptionalTypeBundleSourceSignatureOptions.allocationSize(value.`signature`) + - FfiConverterOptionalTypeDataReadOptions.allocationSize(value.`dataReadOptions`) + - FfiConverterOptionalTypeHeaderReadOptions.allocationSize(value.`headerReadOptions`) + - FfiConverterOptionalTypeIndexReadOptions.allocationSize(value.`indexReadOptions`) + override fun allocationSize(value: UpdaterInstallTarget) = ( + FfiConverterString.allocationSize(value.`name`) + + FfiConverterOptionalString.allocationSize(value.`version`) ) - override fun write(value: BundleSourceConfig, buf: ByteBuffer) { - FfiConverterString.write(value.`builtinDir`, buf) - FfiConverterString.write(value.`remoteDir`, buf) - FfiConverterOptionalString.write(value.`builtinManifestFilepath`, buf) - FfiConverterOptionalString.write(value.`remoteManifestFilepath`, buf) - FfiConverterOptionalTypeBundleSourceIntegrityOptions.write(value.`integrity`, buf) - FfiConverterOptionalTypeBundleSourceSignatureOptions.write(value.`signature`, buf) - FfiConverterOptionalTypeDataReadOptions.write(value.`dataReadOptions`, buf) - FfiConverterOptionalTypeHeaderReadOptions.write(value.`headerReadOptions`, buf) - FfiConverterOptionalTypeIndexReadOptions.write(value.`indexReadOptions`, buf) + override fun write(value: UpdaterInstallTarget, buf: ByteBuffer) { + FfiConverterString.write(value.`name`, buf) + FfiConverterOptionalString.write(value.`version`, buf) } } -/** - * How bundles are checked against the integrity recorded for them in the manifest when - * they are loaded from disk. - */ -data class BundleSourceIntegrityOptions ( +data class UpdaterIntegrityOptions ( /** * How a bundle's integrity metadata is treated (default: [`IntegrityPolicy::Optional`]). * @@ -8111,84 +9647,53 @@ data class BundleSourceIntegrityOptions ( */ var `policy`: IntegrityPolicy? = null , - /** - * A custom checker that validates bundle bytes against their integrity string - * (default: the built-in checker, which compares the advertised hash). - */ - var `check`: IntegrityCheck? = null - , - /** - * Which bundles are checked on load (default: [`BundleSourceVerifyMode::OnlyRemote`]). - */ - var `checkMode`: BundleSourceVerifyMode? = null + var `algorithm`: IntegrityAlgorithm? = null -): Disposable{ +){ - @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here - override fun destroy() { - - Disposable.destroy( - this.`policy`, - this.`check`, - this.`checkMode` - ) - } - companion object } /** * @suppress */ -public object FfiConverterTypeBundleSourceIntegrityOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleSourceIntegrityOptions { - return BundleSourceIntegrityOptions( +public object FfiConverterTypeUpdaterIntegrityOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterIntegrityOptions { + return UpdaterIntegrityOptions( FfiConverterOptionalTypeIntegrityPolicy.read(buf), - FfiConverterOptionalTypeIntegrityCheck.read(buf), - FfiConverterOptionalTypeBundleSourceVerifyMode.read(buf), + FfiConverterOptionalTypeIntegrityAlgorithm.read(buf), ) } - override fun allocationSize(value: BundleSourceIntegrityOptions) = ( + override fun allocationSize(value: UpdaterIntegrityOptions) = ( FfiConverterOptionalTypeIntegrityPolicy.allocationSize(value.`policy`) + - FfiConverterOptionalTypeIntegrityCheck.allocationSize(value.`check`) + - FfiConverterOptionalTypeBundleSourceVerifyMode.allocationSize(value.`checkMode`) + FfiConverterOptionalTypeIntegrityAlgorithm.allocationSize(value.`algorithm`) ) - override fun write(value: BundleSourceIntegrityOptions, buf: ByteBuffer) { + override fun write(value: UpdaterIntegrityOptions, buf: ByteBuffer) { FfiConverterOptionalTypeIntegrityPolicy.write(value.`policy`, buf) - FfiConverterOptionalTypeIntegrityCheck.write(value.`check`, buf) - FfiConverterOptionalTypeBundleSourceVerifyMode.write(value.`checkMode`, buf) + FfiConverterOptionalTypeIntegrityAlgorithm.write(value.`algorithm`, buf) } } /** - * How bundle signatures are verified when bundles are loaded from disk. - * - * A bundle's signature signs its integrity string (e.g. `sha256:`), not the - * bundle bytes; verifying it proves the integrity string is authentic. It is verified - * independently of the integrity check, so pair it with an enabled - * [`BundleSourceConfig::integrity`] to also authenticate the bytes — signature - * verification alone does not read them. + * Optional configuration for the [`Updater`]. */ -data class BundleSourceSignatureOptions ( +data class UpdaterOptions ( /** - * Verifies that a bundle's integrity string was signed by the matching key — with a - * declarative public key or a custom function (default: off). + * Release channel (e.g. `"stable"`, `"beta"`). Passed as a query parameter to the remote. */ - var `verify`: SignatureVerification? = null + var `channel`: kotlin.String? = null , - /** - * Which bundles have their signature verified on load - * (default: [`BundleSourceVerifyMode::OnlyRemote`]). - */ - var `verifyMode`: BundleSourceVerifyMode? = null + var `integrity`: UpdaterIntegrityOptions? = null + , + var `signature`: UpdaterSignatureOptions? = null ): Disposable{ @@ -8200,8 +9705,9 @@ data class BundleSourceSignatureOptions ( override fun destroy() { Disposable.destroy( - this.`verify`, - this.`verifyMode` + this.`channel`, + this.`integrity`, + this.`signature` ) } @@ -8211,34 +9717,38 @@ data class BundleSourceSignatureOptions ( /** * @suppress */ -public object FfiConverterTypeBundleSourceSignatureOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleSourceSignatureOptions { - return BundleSourceSignatureOptions( - FfiConverterOptionalTypeSignatureVerification.read(buf), - FfiConverterOptionalTypeBundleSourceVerifyMode.read(buf), +public object FfiConverterTypeUpdaterOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterOptions { + return UpdaterOptions( + FfiConverterOptionalString.read(buf), + FfiConverterOptionalTypeUpdaterIntegrityOptions.read(buf), + FfiConverterOptionalTypeUpdaterSignatureOptions.read(buf), ) } - override fun allocationSize(value: BundleSourceSignatureOptions) = ( - FfiConverterOptionalTypeSignatureVerification.allocationSize(value.`verify`) + - FfiConverterOptionalTypeBundleSourceVerifyMode.allocationSize(value.`verifyMode`) + override fun allocationSize(value: UpdaterOptions) = ( + FfiConverterOptionalString.allocationSize(value.`channel`) + + FfiConverterOptionalTypeUpdaterIntegrityOptions.allocationSize(value.`integrity`) + + FfiConverterOptionalTypeUpdaterSignatureOptions.allocationSize(value.`signature`) ) - override fun write(value: BundleSourceSignatureOptions, buf: ByteBuffer) { - FfiConverterOptionalTypeSignatureVerification.write(value.`verify`, buf) - FfiConverterOptionalTypeBundleSourceVerifyMode.write(value.`verifyMode`, buf) + override fun write(value: UpdaterOptions, buf: ByteBuffer) { + FfiConverterOptionalString.write(value.`channel`, buf) + FfiConverterOptionalTypeUpdaterIntegrityOptions.write(value.`integrity`, buf) + FfiConverterOptionalTypeUpdaterSignatureOptions.write(value.`signature`, buf) } } -/** - * The currently active version of a bundle and where it was loaded from. - */ -data class BundleSourceVersion ( - var `kind`: BundleSourceKind +data class UpdaterRollbackResult ( + var `name`: kotlin.String , - var `version`: kotlin.String + var `targetVersion`: kotlin.String? + , + var `rollbackVersion`: kotlin.String? + , + var `result`: UpdaterRollbackResultKind ){ @@ -8252,50 +9762,37 @@ data class BundleSourceVersion ( /** * @suppress */ -public object FfiConverterTypeBundleSourceVersion: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleSourceVersion { - return BundleSourceVersion( - FfiConverterTypeBundleSourceKind.read(buf), +public object FfiConverterTypeUpdaterRollbackResult: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterRollbackResult { + return UpdaterRollbackResult( FfiConverterString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterOptionalString.read(buf), + FfiConverterTypeUpdaterRollbackResultKind.read(buf), ) } - override fun allocationSize(value: BundleSourceVersion) = ( - FfiConverterTypeBundleSourceKind.allocationSize(value.`kind`) + - FfiConverterString.allocationSize(value.`version`) + override fun allocationSize(value: UpdaterRollbackResult) = ( + FfiConverterString.allocationSize(value.`name`) + + FfiConverterOptionalString.allocationSize(value.`targetVersion`) + + FfiConverterOptionalString.allocationSize(value.`rollbackVersion`) + + FfiConverterTypeUpdaterRollbackResultKind.allocationSize(value.`result`) ) - override fun write(value: BundleSourceVersion, buf: ByteBuffer) { - FfiConverterTypeBundleSourceKind.write(value.`kind`, buf) - FfiConverterString.write(value.`version`, buf) + override fun write(value: UpdaterRollbackResult, buf: ByteBuffer) { + FfiConverterString.write(value.`name`, buf) + FfiConverterOptionalString.write(value.`targetVersion`, buf) + FfiConverterOptionalString.write(value.`rollbackVersion`, buf) + FfiConverterTypeUpdaterRollbackResultKind.write(value.`result`, buf) } } -/** - * Result of checking whether a bundle update is available. - * - * `is_available` is `true` when `version` differs from `local_version`. - * The `etag`, `integrity`, `signature`, and `last_modified` fields can be - * passed to [`BundleSource::write_remote_bundle`] after downloading. - */ -data class BundleUpdateInfo ( +data class UpdaterRollbackTarget ( var `name`: kotlin.String , - var `version`: kotlin.String - , - var `localVersion`: kotlin.String? - , - var `isAvailable`: kotlin.Boolean - , - var `etag`: kotlin.String? - , - var `integrity`: kotlin.String? - , - var `signature`: kotlin.String? - , - var `lastModified`: kotlin.String? + var `version`: kotlin.String? ){ @@ -8309,1091 +9806,1271 @@ data class BundleUpdateInfo ( /** * @suppress */ -public object FfiConverterTypeBundleUpdateInfo: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleUpdateInfo { - return BundleUpdateInfo( +public object FfiConverterTypeUpdaterRollbackTarget: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterRollbackTarget { + return UpdaterRollbackTarget( FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterBoolean.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), FfiConverterOptionalString.read(buf), ) } - override fun allocationSize(value: BundleUpdateInfo) = ( + override fun allocationSize(value: UpdaterRollbackTarget) = ( FfiConverterString.allocationSize(value.`name`) + - FfiConverterString.allocationSize(value.`version`) + - FfiConverterOptionalString.allocationSize(value.`localVersion`) + - FfiConverterBoolean.allocationSize(value.`isAvailable`) + - FfiConverterOptionalString.allocationSize(value.`etag`) + - FfiConverterOptionalString.allocationSize(value.`integrity`) + - FfiConverterOptionalString.allocationSize(value.`signature`) + - FfiConverterOptionalString.allocationSize(value.`lastModified`) + FfiConverterOptionalString.allocationSize(value.`version`) ) - override fun write(value: BundleUpdateInfo, buf: ByteBuffer) { + override fun write(value: UpdaterRollbackTarget, buf: ByteBuffer) { FfiConverterString.write(value.`name`, buf) - FfiConverterString.write(value.`version`, buf) - FfiConverterOptionalString.write(value.`localVersion`, buf) - FfiConverterBoolean.write(value.`isAvailable`, buf) - FfiConverterOptionalString.write(value.`etag`, buf) - FfiConverterOptionalString.write(value.`integrity`, buf) - FfiConverterOptionalString.write(value.`signature`, buf) - FfiConverterOptionalString.write(value.`lastModified`, buf) + FfiConverterOptionalString.write(value.`version`, buf) } } -/** - * How each entry's xxHash-32 data checksum is verified when its data is read. - */ -data class ChecksumReadOptions ( - /** - * Verify each entry's data checksum when its data is read (default: `true`). - */ - var `verify`: kotlin.Boolean? = null - , - /** - * The seed the data checksums were built with (default: `0`). - */ - var `seed`: kotlin.UInt? = null +data class UpdaterSignatureOptions ( + var `keys`: List? = null -){ +): Disposable{ + @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here + override fun destroy() { + + Disposable.destroy( + this.`keys` + ) + } + companion object } /** * @suppress */ -public object FfiConverterTypeChecksumReadOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ChecksumReadOptions { - return ChecksumReadOptions( - FfiConverterOptionalBoolean.read(buf), - FfiConverterOptionalUInt.read(buf), +public object FfiConverterTypeUpdaterSignatureOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterSignatureOptions { + return UpdaterSignatureOptions( + FfiConverterOptionalSequenceTypeSignatureVerifyKey.read(buf), ) } - override fun allocationSize(value: ChecksumReadOptions) = ( - FfiConverterOptionalBoolean.allocationSize(value.`verify`) + - FfiConverterOptionalUInt.allocationSize(value.`seed`) + override fun allocationSize(value: UpdaterSignatureOptions) = ( + FfiConverterOptionalSequenceTypeSignatureVerifyKey.allocationSize(value.`keys`) ) - override fun write(value: ChecksumReadOptions, buf: ByteBuffer) { - FfiConverterOptionalBoolean.write(value.`verify`, buf) - FfiConverterOptionalUInt.write(value.`seed`, buf) + override fun write(value: UpdaterSignatureOptions, buf: ByteBuffer) { + FfiConverterOptionalSequenceTypeSignatureVerifyKey.write(value.`keys`, buf) } } -data class ChecksumWriteOptions ( +/** + * How the bundle name is resolved from the request uri. + */ +sealed class BundleResolver { + /** - * The seed the data checksums were built with (default: `0`). + * From the uri hostname. + * + * - `segment`: which part of the host to use (default: [`HostnameSegment::First`]). + * - `allow_wvb_suffix_only`: only resolve hosts ending in `.wvb` (default: false). */ - var `seed`: kotlin.UInt? = null + data class Hostname( + val `segment`: dev.wvb.HostnameSegment?, + val `allowWvbSuffixOnly`: kotlin.Boolean?) : BundleResolver() + + { + + + companion object + } -){ + /** + * From the uri pathname. + * + * - `segment_index`: 0-based over non-empty path segments (default: 0). + * e.g. `app://_/my-app/index.html` with index 0 -> bundle `my-app`. + */ + data class Pathname( + val `segmentIndex`: kotlin.UInt?) : BundleResolver() + + { + + + companion object + } + + + companion object } /** * @suppress */ -public object FfiConverterTypeChecksumWriteOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ChecksumWriteOptions { - return ChecksumWriteOptions( - FfiConverterOptionalUInt.read(buf), - ) +public object FfiConverterTypeBundleResolver : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): BundleResolver { + return when(buf.getInt()) { + 1 -> BundleResolver.Hostname( + FfiConverterOptionalTypeHostnameSegment.read(buf), + FfiConverterOptionalBoolean.read(buf), + ) + 2 -> BundleResolver.Pathname( + FfiConverterOptionalUInt.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } } - override fun allocationSize(value: ChecksumWriteOptions) = ( - FfiConverterOptionalUInt.allocationSize(value.`seed`) - ) + override fun allocationSize(value: BundleResolver) = when(value) { + is BundleResolver.Hostname -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalTypeHostnameSegment.allocationSize(value.`segment`) + + FfiConverterOptionalBoolean.allocationSize(value.`allowWvbSuffixOnly`) + ) + } + is BundleResolver.Pathname -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterOptionalUInt.allocationSize(value.`segmentIndex`) + ) + } + } - override fun write(value: ChecksumWriteOptions, buf: ByteBuffer) { - FfiConverterOptionalUInt.write(value.`seed`, buf) + override fun write(value: BundleResolver, buf: ByteBuffer) { + when(value) { + is BundleResolver.Hostname -> { + buf.putInt(1) + FfiConverterOptionalTypeHostnameSegment.write(value.`segment`, buf) + FfiConverterOptionalBoolean.write(value.`allowWvbSuffixOnly`, buf) + Unit + } + is BundleResolver.Pathname -> { + buf.putInt(2) + FfiConverterOptionalUInt.write(value.`segmentIndex`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } -/** - * How each entry's data checksum is verified when its data is read. - */ -data class DataReadOptions ( - /** - * How each entry's data checksum is verified. - */ - var `checksum`: ChecksumReadOptions? = null - -){ - - +sealed class EcdsaVerifyingKey { - companion object -} + data class Sec1( + val `der`: kotlin.ByteArray) : EcdsaVerifyingKey() + + { + -/** - * @suppress - */ -public object FfiConverterTypeDataReadOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): DataReadOptions { - return DataReadOptions( - FfiConverterOptionalTypeChecksumReadOptions.read(buf), - ) + companion object } + + data class SpkiDer( + val `der`: kotlin.ByteArray) : EcdsaVerifyingKey() + + { + - override fun allocationSize(value: DataReadOptions) = ( - FfiConverterOptionalTypeChecksumReadOptions.allocationSize(value.`checksum`) - ) - - override fun write(value: DataReadOptions, buf: ByteBuffer) { - FfiConverterOptionalTypeChecksumReadOptions.write(value.`checksum`, buf) + companion object } -} - - - -/** - * Result of a bundle download containing the parsed bundle, its raw bytes, - * and the server-provided metadata. - * - * `data` holds the raw `.wvb` bytes as received from the server, which callers - * can persist to disk via [`BundleSource::write_remote_bundle`]. - */ -data class DownloadResult ( - var `info`: RemoteBundleInfo - , - var `bundle`: Bundle - , - var `data`: kotlin.ByteArray -): Disposable{ + data class SpkiPem( + val `pem`: kotlin.String) : EcdsaVerifyingKey() + + { + + + companion object + } - @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here - override fun destroy() { - - Disposable.destroy( - this.`info`, - this.`bundle`, - this.`data` - ) - } + + companion object } /** * @suppress */ -public object FfiConverterTypeDownloadResult: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): DownloadResult { - return DownloadResult( - FfiConverterTypeRemoteBundleInfo.read(buf), - FfiConverterTypeBundle.read(buf), - FfiConverterByteArray.read(buf), - ) +public object FfiConverterTypeEcdsaVerifyingKey : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): EcdsaVerifyingKey { + return when(buf.getInt()) { + 1 -> EcdsaVerifyingKey.Sec1( + FfiConverterByteArray.read(buf), + ) + 2 -> EcdsaVerifyingKey.SpkiDer( + FfiConverterByteArray.read(buf), + ) + 3 -> EcdsaVerifyingKey.SpkiPem( + FfiConverterString.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } } - override fun allocationSize(value: DownloadResult) = ( - FfiConverterTypeRemoteBundleInfo.allocationSize(value.`info`) + - FfiConverterTypeBundle.allocationSize(value.`bundle`) + - FfiConverterByteArray.allocationSize(value.`data`) - ) + override fun allocationSize(value: EcdsaVerifyingKey) = when(value) { + is EcdsaVerifyingKey.Sec1 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterByteArray.allocationSize(value.`der`) + ) + } + is EcdsaVerifyingKey.SpkiDer -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterByteArray.allocationSize(value.`der`) + ) + } + is EcdsaVerifyingKey.SpkiPem -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`pem`) + ) + } + } - override fun write(value: DownloadResult, buf: ByteBuffer) { - FfiConverterTypeRemoteBundleInfo.write(value.`info`, buf) - FfiConverterTypeBundle.write(value.`bundle`, buf) - FfiConverterByteArray.write(value.`data`, buf) + override fun write(value: EcdsaVerifyingKey, buf: ByteBuffer) { + when(value) { + is EcdsaVerifyingKey.Sec1 -> { + buf.putInt(1) + FfiConverterByteArray.write(value.`der`, buf) + Unit + } + is EcdsaVerifyingKey.SpkiDer -> { + buf.putInt(2) + FfiConverterByteArray.write(value.`der`, buf) + Unit + } + is EcdsaVerifyingKey.SpkiPem -> { + buf.putInt(3) + FfiConverterString.write(value.`pem`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } -/** - * How a bundle's header checksum is verified when its header is read. - */ -data class HeaderReadOptions ( - /** - * How the header checksum is verified. - */ - var `checksum`: ChecksumReadOptions? = null - -){ - - +sealed class Ed25519VerifyingKey { - companion object -} + data class Raw( + val `bytes`: kotlin.ByteArray) : Ed25519VerifyingKey() + + { + -/** - * @suppress - */ -public object FfiConverterTypeHeaderReadOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): HeaderReadOptions { - return HeaderReadOptions( - FfiConverterOptionalTypeChecksumReadOptions.read(buf), - ) + companion object } + + data class SpkiDer( + val `der`: kotlin.ByteArray) : Ed25519VerifyingKey() + + { + - override fun allocationSize(value: HeaderReadOptions) = ( - FfiConverterOptionalTypeChecksumReadOptions.allocationSize(value.`checksum`) - ) - - override fun write(value: HeaderReadOptions, buf: ByteBuffer) { - FfiConverterOptionalTypeChecksumReadOptions.write(value.`checksum`, buf) + companion object } -} + + data class SpkiPem( + val `pem`: kotlin.String) : Ed25519VerifyingKey() + + { + + companion object + } + + -/** - * HTTP client options - */ -data class HttpOptions ( - /** - * Headers sent with every request. - */ - var `defaultHeaders`: Map? = null - , - var `userAgent`: kotlin.String? = null - , - /** - * Total request timeout in milliseconds (default: `120000`). - * - * Bounds an otherwise-unbounded download: without it a stalled transfer would hang - * forever and keep holding the updater's per-bundle lock. - */ - var `timeout`: kotlin.ULong? = null - , - /** - * Timeout in milliseconds for reading the response body. - */ - var `readTimeout`: kotlin.ULong? = null - , - /** - * Timeout in milliseconds for establishing the connection. - */ - var `connectTimeout`: kotlin.ULong? = null - , - var `poolIdleTimeout`: kotlin.ULong? = null - , - var `poolMaxIdlePerHost`: kotlin.UInt? = null - , - var `referer`: kotlin.Boolean? = null - , - var `tcpNodelay`: kotlin.Boolean? = null -){ - - companion object } /** * @suppress */ -public object FfiConverterTypeHttpOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): HttpOptions { - return HttpOptions( - FfiConverterOptionalMapStringString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterOptionalUInt.read(buf), - FfiConverterOptionalBoolean.read(buf), - FfiConverterOptionalBoolean.read(buf), - ) +public object FfiConverterTypeEd25519VerifyingKey : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): Ed25519VerifyingKey { + return when(buf.getInt()) { + 1 -> Ed25519VerifyingKey.Raw( + FfiConverterByteArray.read(buf), + ) + 2 -> Ed25519VerifyingKey.SpkiDer( + FfiConverterByteArray.read(buf), + ) + 3 -> Ed25519VerifyingKey.SpkiPem( + FfiConverterString.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } } - override fun allocationSize(value: HttpOptions) = ( - FfiConverterOptionalMapStringString.allocationSize(value.`defaultHeaders`) + - FfiConverterOptionalString.allocationSize(value.`userAgent`) + - FfiConverterOptionalULong.allocationSize(value.`timeout`) + - FfiConverterOptionalULong.allocationSize(value.`readTimeout`) + - FfiConverterOptionalULong.allocationSize(value.`connectTimeout`) + - FfiConverterOptionalULong.allocationSize(value.`poolIdleTimeout`) + - FfiConverterOptionalUInt.allocationSize(value.`poolMaxIdlePerHost`) + - FfiConverterOptionalBoolean.allocationSize(value.`referer`) + - FfiConverterOptionalBoolean.allocationSize(value.`tcpNodelay`) - ) + override fun allocationSize(value: Ed25519VerifyingKey) = when(value) { + is Ed25519VerifyingKey.Raw -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterByteArray.allocationSize(value.`bytes`) + ) + } + is Ed25519VerifyingKey.SpkiDer -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterByteArray.allocationSize(value.`der`) + ) + } + is Ed25519VerifyingKey.SpkiPem -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`pem`) + ) + } + } - override fun write(value: HttpOptions, buf: ByteBuffer) { - FfiConverterOptionalMapStringString.write(value.`defaultHeaders`, buf) - FfiConverterOptionalString.write(value.`userAgent`, buf) - FfiConverterOptionalULong.write(value.`timeout`, buf) - FfiConverterOptionalULong.write(value.`readTimeout`, buf) - FfiConverterOptionalULong.write(value.`connectTimeout`, buf) - FfiConverterOptionalULong.write(value.`poolIdleTimeout`, buf) - FfiConverterOptionalUInt.write(value.`poolMaxIdlePerHost`, buf) - FfiConverterOptionalBoolean.write(value.`referer`, buf) - FfiConverterOptionalBoolean.write(value.`tcpNodelay`, buf) + override fun write(value: Ed25519VerifyingKey, buf: ByteBuffer) { + when(value) { + is Ed25519VerifyingKey.Raw -> { + buf.putInt(1) + FfiConverterByteArray.write(value.`bytes`, buf) + Unit + } + is Ed25519VerifyingKey.SpkiDer -> { + buf.putInt(2) + FfiConverterByteArray.write(value.`der`, buf) + Unit + } + is Ed25519VerifyingKey.SpkiPem -> { + buf.putInt(3) + FfiConverterString.write(value.`pem`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } + + /** - * HTTP response returned by protocol handlers. + * Which hostname segment is used as the bundle name. */ -data class HttpResponse ( - var `status`: kotlin.UShort - , - var `headers`: Map - , - var `body`: kotlin.ByteArray +sealed class HostnameSegment { -){ + /** + * First segment. (e.g. `app.mydomain.com` -> `app`) + */ + object First : HostnameSegment() + + + /** + * Full hostname. (e.g. `app.wvb` -> `app.wvb`) + */ + object Full : HostnameSegment() + + + /** + * Strip the last segment. (e.g. `a.b.wvb` -> `a.b`) + */ + object StripSuffix : HostnameSegment() + + + /** + * The nth segment, 0-based. + */ + data class Nth( + val `index`: kotlin.UInt) : HostnameSegment() + + { + + + companion object + } + + + companion object } /** * @suppress */ -public object FfiConverterTypeHttpResponse: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): HttpResponse { - return HttpResponse( - FfiConverterUShort.read(buf), - FfiConverterMapStringString.read(buf), - FfiConverterByteArray.read(buf), - ) +public object FfiConverterTypeHostnameSegment : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): HostnameSegment { + return when(buf.getInt()) { + 1 -> HostnameSegment.First + 2 -> HostnameSegment.Full + 3 -> HostnameSegment.StripSuffix + 4 -> HostnameSegment.Nth( + FfiConverterUInt.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } } - override fun allocationSize(value: HttpResponse) = ( - FfiConverterUShort.allocationSize(value.`status`) + - FfiConverterMapStringString.allocationSize(value.`headers`) + - FfiConverterByteArray.allocationSize(value.`body`) - ) + override fun allocationSize(value: HostnameSegment) = when(value) { + is HostnameSegment.First -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is HostnameSegment.Full -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is HostnameSegment.StripSuffix -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is HostnameSegment.Nth -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterUInt.allocationSize(value.`index`) + ) + } + } - override fun write(value: HttpResponse, buf: ByteBuffer) { - FfiConverterUShort.write(value.`status`, buf) - FfiConverterMapStringString.write(value.`headers`, buf) - FfiConverterByteArray.write(value.`body`, buf) + override fun write(value: HostnameSegment, buf: ByteBuffer) { + when(value) { + is HostnameSegment.First -> { + buf.putInt(1) + Unit + } + is HostnameSegment.Full -> { + buf.putInt(2) + Unit + } + is HostnameSegment.StripSuffix -> { + buf.putInt(3) + Unit + } + is HostnameSegment.Nth -> { + buf.putInt(4) + FfiConverterUInt.write(value.`index`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } + + /** - * Metadata for a single entry stored in the bundle index. - * - * `offset` and `len` refer to the entry's position in the data section. - * `content_length` is the logical (uncompressed) size exposed to HTTP clients, - * which may differ from `len` if the data is stored compressed. + * HTTP request method exposed to FFI consumers. */ -data class IndexEntry ( - var `offset`: kotlin.ULong - , - var `len`: kotlin.ULong - , - var `isEmpty`: kotlin.Boolean - , - var `contentType`: kotlin.String - , - var `contentLength`: kotlin.ULong - , - var `headers`: Map - -){ - +enum class HttpMethod { + GET, + HEAD, + OPTIONS, + POST, + PUT, + PATCH, + DELETE, + TRACE, + CONNECT; + + companion object } + /** * @suppress */ -public object FfiConverterTypeIndexEntry: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): IndexEntry { - return IndexEntry( - FfiConverterULong.read(buf), - FfiConverterULong.read(buf), - FfiConverterBoolean.read(buf), - FfiConverterString.read(buf), - FfiConverterULong.read(buf), - FfiConverterMapStringString.read(buf), - ) +public object FfiConverterTypeHttpMethod: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + HttpMethod.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: IndexEntry) = ( - FfiConverterULong.allocationSize(value.`offset`) + - FfiConverterULong.allocationSize(value.`len`) + - FfiConverterBoolean.allocationSize(value.`isEmpty`) + - FfiConverterString.allocationSize(value.`contentType`) + - FfiConverterULong.allocationSize(value.`contentLength`) + - FfiConverterMapStringString.allocationSize(value.`headers`) - ) + override fun allocationSize(value: HttpMethod) = 4UL - override fun write(value: IndexEntry, buf: ByteBuffer) { - FfiConverterULong.write(value.`offset`, buf) - FfiConverterULong.write(value.`len`, buf) - FfiConverterBoolean.write(value.`isEmpty`, buf) - FfiConverterString.write(value.`contentType`, buf) - FfiConverterULong.write(value.`contentLength`, buf) - FfiConverterMapStringString.write(value.`headers`, buf) + override fun write(value: HttpMethod, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) } } + + /** - * How a bundle's index checksum is verified when its index is read. + * Hash algorithm used to compute the [`Subresource Integrity`](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) digest of a bundle. */ -data class IndexReadOptions ( - /** - * How the index checksum is verified. - */ - var `checksum`: ChecksumReadOptions? = null - -){ - +enum class IntegrityAlgorithm { + SHA256, + SHA384, + SHA512; + + companion object } + /** * @suppress */ -public object FfiConverterTypeIndexReadOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): IndexReadOptions { - return IndexReadOptions( - FfiConverterOptionalTypeChecksumReadOptions.read(buf), - ) +public object FfiConverterTypeIntegrityAlgorithm: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + IntegrityAlgorithm.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: IndexReadOptions) = ( - FfiConverterOptionalTypeChecksumReadOptions.allocationSize(value.`checksum`) - ) + override fun allocationSize(value: IntegrityAlgorithm) = 4UL - override fun write(value: IndexReadOptions, buf: ByteBuffer) { - FfiConverterOptionalTypeChecksumReadOptions.write(value.`checksum`, buf) + override fun write(value: IntegrityAlgorithm, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) } } -data class ListBundleItem ( - var `kind`: BundleSourceKind - , - var `name`: kotlin.String - , - var `version`: kotlin.String - , - var `current`: kotlin.Boolean - , - var `metadata`: BundleManifestMetadata - -){ + + +/** + * How a bundle's integrity metadata is treated when the integrity check runs. + * + * - `Strict`: integrity metadata is required; a bundle without it fails the check. + * - `Optional`: integrity metadata is checked when present and tolerated when missing. + * - `Off`: the integrity check is disabled. + */ + +enum class IntegrityPolicy { + STRICT, + OPTIONAL, + OFF; - + companion object } + /** * @suppress */ -public object FfiConverterTypeListBundleItem: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ListBundleItem { - return ListBundleItem( - FfiConverterTypeBundleSourceKind.read(buf), - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterBoolean.read(buf), - FfiConverterTypeBundleManifestMetadata.read(buf), - ) +public object FfiConverterTypeIntegrityPolicy: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + IntegrityPolicy.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: ListBundleItem) = ( - FfiConverterTypeBundleSourceKind.allocationSize(value.`kind`) + - FfiConverterString.allocationSize(value.`name`) + - FfiConverterString.allocationSize(value.`version`) + - FfiConverterBoolean.allocationSize(value.`current`) + - FfiConverterTypeBundleManifestMetadata.allocationSize(value.`metadata`) - ) + override fun allocationSize(value: IntegrityPolicy) = 4UL - override fun write(value: ListBundleItem, buf: ByteBuffer) { - FfiConverterTypeBundleSourceKind.write(value.`kind`, buf) - FfiConverterString.write(value.`name`, buf) - FfiConverterString.write(value.`version`, buf) - FfiConverterBoolean.write(value.`current`, buf) - FfiConverterTypeBundleManifestMetadata.write(value.`metadata`, buf) + override fun write(value: IntegrityPolicy, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) } } -/** - * Summary of a bundle returned by the remote listing endpoint. - */ -data class ListRemoteBundleInfo ( - var `name`: kotlin.String - , - var `version`: kotlin.String - -){ - + + +enum class ManifestBundleItemStatus { + CURRENT, + PREVIOUS, + STAGED, + ORPHAN; + + companion object } + /** * @suppress */ -public object FfiConverterTypeListRemoteBundleInfo: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ListRemoteBundleInfo { - return ListRemoteBundleInfo( - FfiConverterString.read(buf), - FfiConverterString.read(buf), - ) +public object FfiConverterTypeManifestBundleItemStatus: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + ManifestBundleItemStatus.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: ListRemoteBundleInfo) = ( - FfiConverterString.allocationSize(value.`name`) + - FfiConverterString.allocationSize(value.`version`) - ) + override fun allocationSize(value: ManifestBundleItemStatus) = 4UL - override fun write(value: ListRemoteBundleInfo, buf: ByteBuffer) { - FfiConverterString.write(value.`name`, buf) - FfiConverterString.write(value.`version`, buf) + override fun write(value: ManifestBundleItemStatus, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) } } -/** - * Full metadata returned when fetching or downloading a specific bundle version. - */ -data class RemoteBundleInfo ( - var `name`: kotlin.String - , - var `version`: kotlin.String - , - var `etag`: kotlin.String? - , - var `integrity`: kotlin.String? - , - var `signature`: kotlin.String? - , - var `lastModified`: kotlin.String? - -){ - + + +enum class ManifestRemoveResultKind { + REMOVED, + /** + * The bundle was not exists in the manifest. + */ + NOT_EXISTS, + /** + * The version was not exists in the manifest. + */ + VERSION_NOT_EXISTS, + /** + * The bundle is the current version so that cant be not removed. + * This can be force by enable `force` option. + */ + IN_USE; + + companion object } + /** * @suppress */ -public object FfiConverterTypeRemoteBundleInfo: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): RemoteBundleInfo { - return RemoteBundleInfo( - FfiConverterString.read(buf), - FfiConverterString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalString.read(buf), - ) +public object FfiConverterTypeManifestRemoveResultKind: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + ManifestRemoveResultKind.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: RemoteBundleInfo) = ( - FfiConverterString.allocationSize(value.`name`) + - FfiConverterString.allocationSize(value.`version`) + - FfiConverterOptionalString.allocationSize(value.`etag`) + - FfiConverterOptionalString.allocationSize(value.`integrity`) + - FfiConverterOptionalString.allocationSize(value.`signature`) + - FfiConverterOptionalString.allocationSize(value.`lastModified`) - ) + override fun allocationSize(value: ManifestRemoveResultKind) = 4UL - override fun write(value: RemoteBundleInfo, buf: ByteBuffer) { - FfiConverterString.write(value.`name`, buf) - FfiConverterString.write(value.`version`, buf) - FfiConverterOptionalString.write(value.`etag`, buf) - FfiConverterOptionalString.write(value.`integrity`, buf) - FfiConverterOptionalString.write(value.`signature`, buf) - FfiConverterOptionalString.write(value.`lastModified`, buf) + override fun write(value: ManifestRemoveResultKind, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) } } -/** - * Options for fetching bundle metadata from the remote. - */ -data class RemoteFetchOptions ( - /** - * Release channel (e.g. `"stable"`, `"beta"`). Passed as a query parameter to the remote. - */ - var `channel`: kotlin.String? = null - -){ - + + +enum class ManifestSetCurrentVersionResultKind { + SETTLED, + NOT_EXISTS, + VERSION_NOT_EXISTS; + + companion object } + /** * @suppress */ -public object FfiConverterTypeRemoteFetchOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): RemoteFetchOptions { - return RemoteFetchOptions( - FfiConverterOptionalString.read(buf), - ) +public object FfiConverterTypeManifestSetCurrentVersionResultKind: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + ManifestSetCurrentVersionResultKind.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: RemoteFetchOptions) = ( - FfiConverterOptionalString.allocationSize(value.`channel`) - ) + override fun allocationSize(value: ManifestSetCurrentVersionResultKind) = 4UL - override fun write(value: RemoteFetchOptions, buf: ByteBuffer) { - FfiConverterOptionalString.write(value.`channel`, buf) + override fun write(value: ManifestSetCurrentVersionResultKind, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) } } -/** - * Progress reported while a bundle is downloading. - */ -data class RemoteOnDownloadData ( - /** - * Bytes downloaded so far. - */ - var `downloadedBytes`: kotlin.ULong - , - /** - * Total bytes to download, when the server advertised a content length. - */ - var `totalBytes`: kotlin.ULong? - , - /** - * The endpoint the bundle is being downloaded from. - */ - var `endpoint`: kotlin.String - -){ - + + +enum class ManifestStageResultKind { + STAGED, + IN_USE; + + companion object } + /** * @suppress */ -public object FfiConverterTypeRemoteOnDownloadData: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): RemoteOnDownloadData { - return RemoteOnDownloadData( - FfiConverterULong.read(buf), - FfiConverterOptionalULong.read(buf), - FfiConverterString.read(buf), - ) +public object FfiConverterTypeManifestStageResultKind: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + ManifestStageResultKind.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: RemoteOnDownloadData) = ( - FfiConverterULong.allocationSize(value.`downloadedBytes`) + - FfiConverterOptionalULong.allocationSize(value.`totalBytes`) + - FfiConverterString.allocationSize(value.`endpoint`) - ) + override fun allocationSize(value: ManifestStageResultKind) = 4UL - override fun write(value: RemoteOnDownloadData, buf: ByteBuffer) { - FfiConverterULong.write(value.`downloadedBytes`, buf) - FfiConverterOptionalULong.write(value.`totalBytes`, buf) - FfiConverterString.write(value.`endpoint`, buf) + override fun write(value: ManifestStageResultKind, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) } } + + /** - * Options for creating a [`Remote`] client. + * How the file path in the bundle is resolved from the request uri. */ -data class RemoteOptions ( + +enum class PathResolver { + /** - * HTTP client options. + * Use the uri path as-is (only percent-decoded). */ - var `http`: HttpOptions? = null - , + EXACT, /** - * Download progress callback. + * Directory index: `/` -> `/index.html` and `/about` -> `/about/index.html`. */ - var `onDownload`: RemoteOnDownload? = null - -): Disposable{ - + DIRECTORY_INDEX, + /** + * `.html` extension: `/` -> `/index.html` and `/about` -> `/about.html`. + */ + HTML_EXTENSION; - - @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here - override fun destroy() { - - Disposable.destroy( - this.`http`, - this.`onDownload` - ) - } - + companion object } + /** * @suppress */ -public object FfiConverterTypeRemoteOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): RemoteOptions { - return RemoteOptions( - FfiConverterOptionalTypeHttpOptions.read(buf), - FfiConverterOptionalTypeRemoteOnDownload.read(buf), - ) +public object FfiConverterTypePathResolver: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + PathResolver.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: RemoteOptions) = ( - FfiConverterOptionalTypeHttpOptions.allocationSize(value.`http`) + - FfiConverterOptionalTypeRemoteOnDownload.allocationSize(value.`onDownload`) - ) + override fun allocationSize(value: PathResolver) = 4UL - override fun write(value: RemoteOptions, buf: ByteBuffer) { - FfiConverterOptionalTypeHttpOptions.write(value.`http`, buf) - FfiConverterOptionalTypeRemoteOnDownload.write(value.`onDownload`, buf) + override fun write(value: PathResolver, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) } } -/** - * Configuration passed to the updater to enable signature verification. - */ -data class SignatureVerifierOptions ( - var `algorithm`: SignatureAlgorithm - , - var `key`: SignatureVerifyingKey - -){ - - +sealed class RsaVerifyingKey { - companion object -} + data class Pkcs1Der( + val `der`: kotlin.ByteArray) : RsaVerifyingKey() + + { + -/** - * @suppress - */ -public object FfiConverterTypeSignatureVerifierOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): SignatureVerifierOptions { - return SignatureVerifierOptions( - FfiConverterTypeSignatureAlgorithm.read(buf), - FfiConverterTypeSignatureVerifyingKey.read(buf), - ) + companion object } + + data class Pkcs1Pem( + val `pem`: kotlin.String) : RsaVerifyingKey() + + { + - override fun allocationSize(value: SignatureVerifierOptions) = ( - FfiConverterTypeSignatureAlgorithm.allocationSize(value.`algorithm`) + - FfiConverterTypeSignatureVerifyingKey.allocationSize(value.`key`) - ) - - override fun write(value: SignatureVerifierOptions, buf: ByteBuffer) { - FfiConverterTypeSignatureAlgorithm.write(value.`algorithm`, buf) - FfiConverterTypeSignatureVerifyingKey.write(value.`key`, buf) + companion object } -} - - + + data class SpkiDer( + val `der`: kotlin.ByteArray) : RsaVerifyingKey() + + { + -/** - * Key data for signature verification. - * Use `pem` for PEM-encoded text keys, `der` for DER/raw binary keys. - */ -data class SignatureVerifyingKey ( - var `format`: VerifyingKeyFormat - , - var `pem`: kotlin.String? - , - var `der`: kotlin.ByteArray? + companion object + } -){ + data class SpkiPem( + val `pem`: kotlin.String) : RsaVerifyingKey() + + { + + + companion object + } + + + companion object } /** * @suppress */ -public object FfiConverterTypeSignatureVerifyingKey: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): SignatureVerifyingKey { - return SignatureVerifyingKey( - FfiConverterTypeVerifyingKeyFormat.read(buf), - FfiConverterOptionalString.read(buf), - FfiConverterOptionalByteArray.read(buf), - ) +public object FfiConverterTypeRsaVerifyingKey : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): RsaVerifyingKey { + return when(buf.getInt()) { + 1 -> RsaVerifyingKey.Pkcs1Der( + FfiConverterByteArray.read(buf), + ) + 2 -> RsaVerifyingKey.Pkcs1Pem( + FfiConverterString.read(buf), + ) + 3 -> RsaVerifyingKey.SpkiDer( + FfiConverterByteArray.read(buf), + ) + 4 -> RsaVerifyingKey.SpkiPem( + FfiConverterString.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } } - override fun allocationSize(value: SignatureVerifyingKey) = ( - FfiConverterTypeVerifyingKeyFormat.allocationSize(value.`format`) + - FfiConverterOptionalString.allocationSize(value.`pem`) + - FfiConverterOptionalByteArray.allocationSize(value.`der`) - ) + override fun allocationSize(value: RsaVerifyingKey) = when(value) { + is RsaVerifyingKey.Pkcs1Der -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterByteArray.allocationSize(value.`der`) + ) + } + is RsaVerifyingKey.Pkcs1Pem -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`pem`) + ) + } + is RsaVerifyingKey.SpkiDer -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterByteArray.allocationSize(value.`der`) + ) + } + is RsaVerifyingKey.SpkiPem -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterString.allocationSize(value.`pem`) + ) + } + } - override fun write(value: SignatureVerifyingKey, buf: ByteBuffer) { - FfiConverterTypeVerifyingKeyFormat.write(value.`format`, buf) - FfiConverterOptionalString.write(value.`pem`, buf) - FfiConverterOptionalByteArray.write(value.`der`, buf) + override fun write(value: RsaVerifyingKey, buf: ByteBuffer) { + when(value) { + is RsaVerifyingKey.Pkcs1Der -> { + buf.putInt(1) + FfiConverterByteArray.write(value.`der`, buf) + Unit + } + is RsaVerifyingKey.Pkcs1Pem -> { + buf.putInt(2) + FfiConverterString.write(value.`pem`, buf) + Unit + } + is RsaVerifyingKey.SpkiDer -> { + buf.putInt(3) + FfiConverterByteArray.write(value.`der`, buf) + Unit + } + is RsaVerifyingKey.SpkiPem -> { + buf.putInt(4) + FfiConverterString.write(value.`pem`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } -data class UpdaterIntegrityOptions ( - /** - * How a bundle's integrity metadata is treated (default: [`IntegrityPolicy::Optional`]). - * - * [`IntegrityPolicy::Off`] disables the integrity check entirely. - */ - var `policy`: IntegrityPolicy? = null - , - /** - * A custom checker that validates bundle bytes against their integrity string - * (default: the built-in checker, which compares the advertised hash). - */ - var `check`: IntegrityCheck? = null + + +sealed class SignatureVerify: Disposable { -): Disposable{ + data class EcdsaSecp256r1( + val `key`: dev.wvb.EcdsaVerifyingKey) : SignatureVerify() + + { + + + companion object + } + + data class EcdsaSecp384r1( + val `key`: dev.wvb.EcdsaVerifyingKey) : SignatureVerify() + + { + + + companion object + } + + data class Ed25519( + val `key`: dev.wvb.Ed25519VerifyingKey) : SignatureVerify() + + { + + + companion object + } + + data class RsaPkcs1V15Sha256( + val `key`: dev.wvb.RsaVerifyingKey) : SignatureVerify() + + { + + + companion object + } + data class RsaPssSha256( + val `key`: dev.wvb.RsaVerifyingKey) : SignatureVerify() + + { + + + companion object + } + + data class Custom( + val `verify`: dev.wvb.SignatureCustomVerify) : SignatureVerify() + + { + + companion object + } @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here override fun destroy() { - + when(this) { + is SignatureVerify.EcdsaSecp256r1 -> { + + Disposable.destroy( + this.`key` + ) + + } + is SignatureVerify.EcdsaSecp384r1 -> { + + Disposable.destroy( + this.`key` + ) + + } + is SignatureVerify.Ed25519 -> { + + Disposable.destroy( + this.`key` + ) + + } + is SignatureVerify.RsaPkcs1V15Sha256 -> { + + Disposable.destroy( + this.`key` + ) + + } + is SignatureVerify.RsaPssSha256 -> { + + Disposable.destroy( + this.`key` + ) + + } + is SignatureVerify.Custom -> { + Disposable.destroy( - this.`policy`, - this.`check` + this.`verify` ) + + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } + + + + + companion object } /** * @suppress */ -public object FfiConverterTypeUpdaterIntegrityOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): UpdaterIntegrityOptions { - return UpdaterIntegrityOptions( - FfiConverterOptionalTypeIntegrityPolicy.read(buf), - FfiConverterOptionalTypeIntegrityCheck.read(buf), - ) +public object FfiConverterTypeSignatureVerify : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): SignatureVerify { + return when(buf.getInt()) { + 1 -> SignatureVerify.EcdsaSecp256r1( + FfiConverterTypeEcdsaVerifyingKey.read(buf), + ) + 2 -> SignatureVerify.EcdsaSecp384r1( + FfiConverterTypeEcdsaVerifyingKey.read(buf), + ) + 3 -> SignatureVerify.Ed25519( + FfiConverterTypeEd25519VerifyingKey.read(buf), + ) + 4 -> SignatureVerify.RsaPkcs1V15Sha256( + FfiConverterTypeRsaVerifyingKey.read(buf), + ) + 5 -> SignatureVerify.RsaPssSha256( + FfiConverterTypeRsaVerifyingKey.read(buf), + ) + 6 -> SignatureVerify.Custom( + FfiConverterTypeSignatureCustomVerify.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } } - override fun allocationSize(value: UpdaterIntegrityOptions) = ( - FfiConverterOptionalTypeIntegrityPolicy.allocationSize(value.`policy`) + - FfiConverterOptionalTypeIntegrityCheck.allocationSize(value.`check`) - ) + override fun allocationSize(value: SignatureVerify) = when(value) { + is SignatureVerify.EcdsaSecp256r1 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeEcdsaVerifyingKey.allocationSize(value.`key`) + ) + } + is SignatureVerify.EcdsaSecp384r1 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeEcdsaVerifyingKey.allocationSize(value.`key`) + ) + } + is SignatureVerify.Ed25519 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeEd25519VerifyingKey.allocationSize(value.`key`) + ) + } + is SignatureVerify.RsaPkcs1V15Sha256 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeRsaVerifyingKey.allocationSize(value.`key`) + ) + } + is SignatureVerify.RsaPssSha256 -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeRsaVerifyingKey.allocationSize(value.`key`) + ) + } + is SignatureVerify.Custom -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeSignatureCustomVerify.allocationSize(value.`verify`) + ) + } + } - override fun write(value: UpdaterIntegrityOptions, buf: ByteBuffer) { - FfiConverterOptionalTypeIntegrityPolicy.write(value.`policy`, buf) - FfiConverterOptionalTypeIntegrityCheck.write(value.`check`, buf) + override fun write(value: SignatureVerify, buf: ByteBuffer) { + when(value) { + is SignatureVerify.EcdsaSecp256r1 -> { + buf.putInt(1) + FfiConverterTypeEcdsaVerifyingKey.write(value.`key`, buf) + Unit + } + is SignatureVerify.EcdsaSecp384r1 -> { + buf.putInt(2) + FfiConverterTypeEcdsaVerifyingKey.write(value.`key`, buf) + Unit + } + is SignatureVerify.Ed25519 -> { + buf.putInt(3) + FfiConverterTypeEd25519VerifyingKey.write(value.`key`, buf) + Unit + } + is SignatureVerify.RsaPkcs1V15Sha256 -> { + buf.putInt(4) + FfiConverterTypeRsaVerifyingKey.write(value.`key`, buf) + Unit + } + is SignatureVerify.RsaPssSha256 -> { + buf.putInt(5) + FfiConverterTypeRsaVerifyingKey.write(value.`key`, buf) + Unit + } + is SignatureVerify.Custom -> { + buf.putInt(6) + FfiConverterTypeSignatureCustomVerify.write(value.`verify`, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } + + /** - * Optional configuration for the [`Updater`]. + * Which bundles a load-time verification applies to */ -data class UpdaterOptions ( + +enum class SourceIntegrityCheckMode { + /** - * Release channel (e.g. `"stable"`, `"beta"`). Passed as a query parameter to the remote. + * Verify both builtin and remote bundles. + * + * Builtin bundles ship inside the application, so the builtin manifest must carry the + * metadata being verified for the check to have anything to work with. */ - var `channel`: kotlin.String? = null - , - var `integrity`: UpdaterIntegrityOptions? = null - , - var `signature`: UpdaterSignatureOptions? = null - -): Disposable{ - + ALL, + /** + * Verify downloaded (remote) bundles only. This is the default. + */ + ONLY_REMOTE; - - @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here - override fun destroy() { - - Disposable.destroy( - this.`channel`, - this.`integrity`, - this.`signature` - ) - } - + companion object } + /** * @suppress - */ -public object FfiConverterTypeUpdaterOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): UpdaterOptions { - return UpdaterOptions( - FfiConverterOptionalString.read(buf), - FfiConverterOptionalTypeUpdaterIntegrityOptions.read(buf), - FfiConverterOptionalTypeUpdaterSignatureOptions.read(buf), - ) + */ +public object FfiConverterTypeSourceIntegrityCheckMode: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + SourceIntegrityCheckMode.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: UpdaterOptions) = ( - FfiConverterOptionalString.allocationSize(value.`channel`) + - FfiConverterOptionalTypeUpdaterIntegrityOptions.allocationSize(value.`integrity`) + - FfiConverterOptionalTypeUpdaterSignatureOptions.allocationSize(value.`signature`) - ) + override fun allocationSize(value: SourceIntegrityCheckMode) = 4UL - override fun write(value: UpdaterOptions, buf: ByteBuffer) { - FfiConverterOptionalString.write(value.`channel`, buf) - FfiConverterOptionalTypeUpdaterIntegrityOptions.write(value.`integrity`, buf) - FfiConverterOptionalTypeUpdaterSignatureOptions.write(value.`signature`, buf) + override fun write(value: SourceIntegrityCheckMode, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) } } -data class UpdaterSignatureOptions ( - /** - * When set, the updater verifies the bundle signature over its integrity string before - * applying an update — with a declarative public key or a custom function. - * Verified independently of `integrity_policy` — keep the policy enabled for the - * signature to also authenticate the bundle bytes. - */ - var `verify`: SignatureVerification? = null - -): Disposable{ - - +/** + * Whether a bundle was loaded from the builtin (read-only, shipped with the app) + * or the remote (writable, downloaded at runtime) directory. + */ + +enum class SourceKind { - @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here - override fun destroy() { - - Disposable.destroy( - this.`verify` - ) - } + BUILTIN, + REMOTE; + + + companion object } + /** * @suppress */ -public object FfiConverterTypeUpdaterSignatureOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): UpdaterSignatureOptions { - return UpdaterSignatureOptions( - FfiConverterOptionalTypeSignatureVerification.read(buf), - ) +public object FfiConverterTypeSourceKind: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer) = try { + SourceKind.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: UpdaterSignatureOptions) = ( - FfiConverterOptionalTypeSignatureVerification.allocationSize(value.`verify`) - ) + override fun allocationSize(value: SourceKind) = 4UL - override fun write(value: UpdaterSignatureOptions, buf: ByteBuffer) { - FfiConverterOptionalTypeSignatureVerification.write(value.`verify`, buf) + override fun write(value: SourceKind, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) } } -/** - * How the bundle name is resolved from the request uri. - */ -sealed class BundleResolver { - - /** - * From the uri hostname. - * - * - `segment`: which part of the host to use (default: [`HostnameSegment::First`]). - * - `allow_wvb_suffix_only`: only resolve hosts ending in `.wvb` (default: false). - */ - data class Hostname( - val `segment`: dev.wvb.HostnameSegment?, - val `allowWvbSuffixOnly`: kotlin.Boolean?) : BundleResolver() - - { - - companion object - } + +sealed class UpdaterDownloadResultKind { - /** - * From the uri pathname. - * - * - `segment_index`: 0-based over non-empty path segments (default: 0). - * e.g. `app://_/my-app/index.html` with index 0 -> bundle `my-app`. - */ - data class Pathname( - val `segmentIndex`: kotlin.UInt?) : BundleResolver() + object Downloaded : UpdaterDownloadResultKind() + + + data class Error( + val v1: dev.wvb.WebviewBundleException) : UpdaterDownloadResultKind() { @@ -9414,49 +11091,42 @@ sealed class BundleResolver { /** * @suppress */ -public object FfiConverterTypeBundleResolver : FfiConverterRustBuffer{ - override fun read(buf: ByteBuffer): BundleResolver { +public object FfiConverterTypeUpdaterDownloadResultKind : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): UpdaterDownloadResultKind { return when(buf.getInt()) { - 1 -> BundleResolver.Hostname( - FfiConverterOptionalTypeHostnameSegment.read(buf), - FfiConverterOptionalBoolean.read(buf), - ) - 2 -> BundleResolver.Pathname( - FfiConverterOptionalUInt.read(buf), + 1 -> UpdaterDownloadResultKind.Downloaded + 2 -> UpdaterDownloadResultKind.Error( + FfiConverterTypeWebviewBundleError.read(buf), ) else -> throw RuntimeException("invalid enum value, something is very wrong!!") } } - override fun allocationSize(value: BundleResolver) = when(value) { - is BundleResolver.Hostname -> { + override fun allocationSize(value: UpdaterDownloadResultKind) = when(value) { + is UpdaterDownloadResultKind.Downloaded -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( 4UL - + FfiConverterOptionalTypeHostnameSegment.allocationSize(value.`segment`) - + FfiConverterOptionalBoolean.allocationSize(value.`allowWvbSuffixOnly`) ) } - is BundleResolver.Pathname -> { + is UpdaterDownloadResultKind.Error -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( 4UL - + FfiConverterOptionalUInt.allocationSize(value.`segmentIndex`) + + FfiConverterTypeWebviewBundleError.allocationSize(value.v1) ) } } - override fun write(value: BundleResolver, buf: ByteBuffer) { + override fun write(value: UpdaterDownloadResultKind, buf: ByteBuffer) { when(value) { - is BundleResolver.Hostname -> { + is UpdaterDownloadResultKind.Downloaded -> { buf.putInt(1) - FfiConverterOptionalTypeHostnameSegment.write(value.`segment`, buf) - FfiConverterOptionalBoolean.write(value.`allowWvbSuffixOnly`, buf) Unit } - is BundleResolver.Pathname -> { + is UpdaterDownloadResultKind.Error -> { buf.putInt(2) - FfiConverterOptionalUInt.write(value.`segmentIndex`, buf) + FfiConverterTypeWebviewBundleError.write(value.v1, buf) Unit } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } @@ -9467,83 +11137,114 @@ public object FfiConverterTypeBundleResolver : FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - BundleSourceKind.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) - } - - override fun allocationSize(value: BundleSourceKind) = 4UL - - override fun write(value: BundleSourceKind, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) + companion object } -} - - - - - -/** - * Which bundles a load-time verification applies to - */ + -enum class BundleSourceVerifyMode { - /** - * Verify both builtin and remote bundles. - * - * Builtin bundles ship inside the application, so the builtin manifest must carry the - * metadata being verified for the check to have anything to work with. - */ - ALL, - /** - * Verify downloaded (remote) bundles only. This is the default. - */ - ONLY_REMOTE; + companion object } - /** * @suppress */ -public object FfiConverterTypeBundleSourceVerifyMode: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - BundleSourceVerifyMode.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) +public object FfiConverterTypeUpdaterInstallResultKind : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): UpdaterInstallResultKind { + return when(buf.getInt()) { + 1 -> UpdaterInstallResultKind.Installed + 2 -> UpdaterInstallResultKind.StagedVersionNotMatched + 3 -> UpdaterInstallResultKind.StagedBundleNotExists + 4 -> UpdaterInstallResultKind.VerifyFailed + 5 -> UpdaterInstallResultKind.Error( + FfiConverterTypeWebviewBundleError.read(buf), + ) + else -> throw RuntimeException("invalid enum value, something is very wrong!!") + } } - override fun allocationSize(value: BundleSourceVerifyMode) = 4UL + override fun allocationSize(value: UpdaterInstallResultKind) = when(value) { + is UpdaterInstallResultKind.Installed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is UpdaterInstallResultKind.StagedVersionNotMatched -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is UpdaterInstallResultKind.StagedBundleNotExists -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is UpdaterInstallResultKind.VerifyFailed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + ) + } + is UpdaterInstallResultKind.Error -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeWebviewBundleError.allocationSize(value.v1) + ) + } + } - override fun write(value: BundleSourceVerifyMode, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) + override fun write(value: UpdaterInstallResultKind, buf: ByteBuffer) { + when(value) { + is UpdaterInstallResultKind.Installed -> { + buf.putInt(1) + Unit + } + is UpdaterInstallResultKind.StagedVersionNotMatched -> { + buf.putInt(2) + Unit + } + is UpdaterInstallResultKind.StagedBundleNotExists -> { + buf.putInt(3) + Unit + } + is UpdaterInstallResultKind.VerifyFailed -> { + buf.putInt(4) + Unit + } + is UpdaterInstallResultKind.Error -> { + buf.putInt(5) + FfiConverterTypeWebviewBundleError.write(value.v1, buf) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } @@ -9551,34 +11252,22 @@ public object FfiConverterTypeBundleSourceVerifyMode: FfiConverterRustBuffer `app`) - */ - object First : HostnameSegment() + object RolledBack : UpdaterRollbackResultKind() - /** - * Full hostname. (e.g. `app.wvb` -> `app.wvb`) - */ - object Full : HostnameSegment() + object PreviousVersionNotMatched : UpdaterRollbackResultKind() - /** - * Strip the last segment. (e.g. `a.b.wvb` -> `a.b`) - */ - object StripSuffix : HostnameSegment() + object PreviousBundleNotExists : UpdaterRollbackResultKind() - /** - * The nth segment, 0-based. - */ - data class Nth( - val `index`: kotlin.UInt) : HostnameSegment() + object VerifyFailed : UpdaterRollbackResultKind() + + + data class Error( + val v1: dev.wvb.WebviewBundleException) : UpdaterRollbackResultKind() { @@ -9599,64 +11288,75 @@ sealed class HostnameSegment { /** * @suppress */ -public object FfiConverterTypeHostnameSegment : FfiConverterRustBuffer{ - override fun read(buf: ByteBuffer): HostnameSegment { +public object FfiConverterTypeUpdaterRollbackResultKind : FfiConverterRustBuffer{ + override fun read(buf: ByteBuffer): UpdaterRollbackResultKind { return when(buf.getInt()) { - 1 -> HostnameSegment.First - 2 -> HostnameSegment.Full - 3 -> HostnameSegment.StripSuffix - 4 -> HostnameSegment.Nth( - FfiConverterUInt.read(buf), + 1 -> UpdaterRollbackResultKind.RolledBack + 2 -> UpdaterRollbackResultKind.PreviousVersionNotMatched + 3 -> UpdaterRollbackResultKind.PreviousBundleNotExists + 4 -> UpdaterRollbackResultKind.VerifyFailed + 5 -> UpdaterRollbackResultKind.Error( + FfiConverterTypeWebviewBundleError.read(buf), ) else -> throw RuntimeException("invalid enum value, something is very wrong!!") } } - override fun allocationSize(value: HostnameSegment) = when(value) { - is HostnameSegment.First -> { + override fun allocationSize(value: UpdaterRollbackResultKind) = when(value) { + is UpdaterRollbackResultKind.RolledBack -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( 4UL ) } - is HostnameSegment.Full -> { + is UpdaterRollbackResultKind.PreviousVersionNotMatched -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( 4UL ) } - is HostnameSegment.StripSuffix -> { + is UpdaterRollbackResultKind.PreviousBundleNotExists -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( 4UL ) } - is HostnameSegment.Nth -> { + is UpdaterRollbackResultKind.VerifyFailed -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( 4UL - + FfiConverterUInt.allocationSize(value.`index`) + ) + } + is UpdaterRollbackResultKind.Error -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypeWebviewBundleError.allocationSize(value.v1) ) } } - override fun write(value: HostnameSegment, buf: ByteBuffer) { + override fun write(value: UpdaterRollbackResultKind, buf: ByteBuffer) { when(value) { - is HostnameSegment.First -> { + is UpdaterRollbackResultKind.RolledBack -> { buf.putInt(1) Unit } - is HostnameSegment.Full -> { + is UpdaterRollbackResultKind.PreviousVersionNotMatched -> { buf.putInt(2) Unit } - is HostnameSegment.StripSuffix -> { + is UpdaterRollbackResultKind.PreviousBundleNotExists -> { buf.putInt(3) Unit } - is HostnameSegment.Nth -> { - buf.putInt(4) - FfiConverterUInt.write(value.`index`, buf) + is UpdaterRollbackResultKind.VerifyFailed -> { + buf.putInt(4) + Unit + } + is UpdaterRollbackResultKind.Error -> { + buf.putInt(5) + FfiConverterTypeWebviewBundleError.write(value.v1, buf) Unit } }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } @@ -9668,20 +11368,12 @@ public object FfiConverterTypeHostnameSegment : FfiConverterRustBuffer { +public object FfiConverterTypeVersion: FfiConverterRustBuffer { override fun read(buf: ByteBuffer) = try { - HttpMethod.values()[buf.getInt() - 1] + Version.values()[buf.getInt() - 1] } catch (e: IndexOutOfBoundsException) { throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: HttpMethod) = 4UL + override fun allocationSize(value: Version) = 4UL - override fun write(value: HttpMethod, buf: ByteBuffer) { + override fun write(value: Version, buf: ByteBuffer) { buf.putInt(value.ordinal + 1) } } @@ -9711,668 +11403,768 @@ public object FfiConverterTypeHttpMethod: FfiConverterRustBuffer { + + /** - * Hash algorithm used to compute the [`Subresource Integrity`](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) digest of a bundle. + * WebviewBundle Error. + */ +sealed class WebviewBundleException(message: String): kotlin.Exception(message) { + + class CoreIo(message: String) : WebviewBundleException(message) + + class CoreCompress(message: String) : WebviewBundleException(message) + + class CoreDecompress(message: String) : WebviewBundleException(message) + + class CoreEncode(message: String) : WebviewBundleException(message) + + class CoreDecode(message: String) : WebviewBundleException(message) + + class CoreHttp(message: String) : WebviewBundleException(message) + + class CoreHttpInvalidUri(message: String) : WebviewBundleException(message) + + class CoreCancelled(message: String) : WebviewBundleException(message) + + class CoreTimeout(message: String) : WebviewBundleException(message) + + class CoreInvalidMagicNum(message: String) : WebviewBundleException(message) + + class CoreInvalidVersion(message: String) : WebviewBundleException(message) + + class CoreInvalidHeaderChecksum(message: String) : WebviewBundleException(message) + + class CoreInvalidIndexChecksum(message: String) : WebviewBundleException(message) + + class CoreChecksumMismatch(message: String) : WebviewBundleException(message) + + class CoreBundleNotFound(message: String) : WebviewBundleException(message) + + class CoreInvalidFilepath(message: String) : WebviewBundleException(message) + + class CoreSerdeJson(message: String) : WebviewBundleException(message) + + class CoreCannotResolveProxyServer(message: String) : WebviewBundleException(message) + + class CoreHttpClient(message: String) : WebviewBundleException(message) + + class CoreRemoteHttp(message: String) : WebviewBundleException(message) + + class CoreBadRemoteResponse(message: String) : WebviewBundleException(message) + + class CoreInvalidRemoteConfig(message: String) : WebviewBundleException(message) + + class CoreInvalidUpdaterConfig(message: String) : WebviewBundleException(message) + + class CoreInvalidIntegrity(message: String) : WebviewBundleException(message) + + class CoreIntegrityRequired(message: String) : WebviewBundleException(message) + + class CoreIntegrityVerifyFailed(message: String) : WebviewBundleException(message) + + class CoreInvalidSignature(message: String) : WebviewBundleException(message) + + class CoreInvalidSignatureKey(message: String) : WebviewBundleException(message) + + class CoreExpectSignatureNotFound(message: String) : WebviewBundleException(message) + + class CoreSignatureVerifyFailed(message: String) : WebviewBundleException(message) + + class CoreGeneric(message: String) : WebviewBundleException(message) + + /** + * Invalid HTTP header name. + */ + class BindingInvalidHeaderName(message: String) : WebviewBundleException(message) + + /** + * Invalid HTTP header value. + */ + class BindingInvalidHeaderValue(message: String) : WebviewBundleException(message) + + /** + * The signature verify options passed across the boundary could not be turned into a + * verifier (a key of the wrong shape, or one the algorithm cannot read). + */ + class BindingInvalidSignatureOptions(message: String) : WebviewBundleException(message) + + + companion object ErrorHandler : UniffiRustCallStatusErrorHandler { + override fun lift(error_buf: RustBuffer.ByValue): WebviewBundleException = FfiConverterTypeWebviewBundleError.lift(error_buf) + } +} + +/** + * @suppress */ +public object FfiConverterTypeWebviewBundleError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): WebviewBundleException { + + return when(buf.getInt()) { + 1 -> WebviewBundleException.CoreIo(FfiConverterString.read(buf)) + 2 -> WebviewBundleException.CoreCompress(FfiConverterString.read(buf)) + 3 -> WebviewBundleException.CoreDecompress(FfiConverterString.read(buf)) + 4 -> WebviewBundleException.CoreEncode(FfiConverterString.read(buf)) + 5 -> WebviewBundleException.CoreDecode(FfiConverterString.read(buf)) + 6 -> WebviewBundleException.CoreHttp(FfiConverterString.read(buf)) + 7 -> WebviewBundleException.CoreHttpInvalidUri(FfiConverterString.read(buf)) + 8 -> WebviewBundleException.CoreCancelled(FfiConverterString.read(buf)) + 9 -> WebviewBundleException.CoreTimeout(FfiConverterString.read(buf)) + 10 -> WebviewBundleException.CoreInvalidMagicNum(FfiConverterString.read(buf)) + 11 -> WebviewBundleException.CoreInvalidVersion(FfiConverterString.read(buf)) + 12 -> WebviewBundleException.CoreInvalidHeaderChecksum(FfiConverterString.read(buf)) + 13 -> WebviewBundleException.CoreInvalidIndexChecksum(FfiConverterString.read(buf)) + 14 -> WebviewBundleException.CoreChecksumMismatch(FfiConverterString.read(buf)) + 15 -> WebviewBundleException.CoreBundleNotFound(FfiConverterString.read(buf)) + 16 -> WebviewBundleException.CoreInvalidFilepath(FfiConverterString.read(buf)) + 17 -> WebviewBundleException.CoreSerdeJson(FfiConverterString.read(buf)) + 18 -> WebviewBundleException.CoreCannotResolveProxyServer(FfiConverterString.read(buf)) + 19 -> WebviewBundleException.CoreHttpClient(FfiConverterString.read(buf)) + 20 -> WebviewBundleException.CoreRemoteHttp(FfiConverterString.read(buf)) + 21 -> WebviewBundleException.CoreBadRemoteResponse(FfiConverterString.read(buf)) + 22 -> WebviewBundleException.CoreInvalidRemoteConfig(FfiConverterString.read(buf)) + 23 -> WebviewBundleException.CoreInvalidUpdaterConfig(FfiConverterString.read(buf)) + 24 -> WebviewBundleException.CoreInvalidIntegrity(FfiConverterString.read(buf)) + 25 -> WebviewBundleException.CoreIntegrityRequired(FfiConverterString.read(buf)) + 26 -> WebviewBundleException.CoreIntegrityVerifyFailed(FfiConverterString.read(buf)) + 27 -> WebviewBundleException.CoreInvalidSignature(FfiConverterString.read(buf)) + 28 -> WebviewBundleException.CoreInvalidSignatureKey(FfiConverterString.read(buf)) + 29 -> WebviewBundleException.CoreExpectSignatureNotFound(FfiConverterString.read(buf)) + 30 -> WebviewBundleException.CoreSignatureVerifyFailed(FfiConverterString.read(buf)) + 31 -> WebviewBundleException.CoreGeneric(FfiConverterString.read(buf)) + 32 -> WebviewBundleException.BindingInvalidHeaderName(FfiConverterString.read(buf)) + 33 -> WebviewBundleException.BindingInvalidHeaderValue(FfiConverterString.read(buf)) + 34 -> WebviewBundleException.BindingInvalidSignatureOptions(FfiConverterString.read(buf)) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") + } + + } -enum class IntegrityAlgorithm { - - SHA256, - SHA384, - SHA512; + override fun allocationSize(value: WebviewBundleException): ULong { + return 4UL + } + + override fun write(value: WebviewBundleException, buf: ByteBuffer) { + when(value) { + is WebviewBundleException.CoreIo -> { + buf.putInt(1) + Unit + } + is WebviewBundleException.CoreCompress -> { + buf.putInt(2) + Unit + } + is WebviewBundleException.CoreDecompress -> { + buf.putInt(3) + Unit + } + is WebviewBundleException.CoreEncode -> { + buf.putInt(4) + Unit + } + is WebviewBundleException.CoreDecode -> { + buf.putInt(5) + Unit + } + is WebviewBundleException.CoreHttp -> { + buf.putInt(6) + Unit + } + is WebviewBundleException.CoreHttpInvalidUri -> { + buf.putInt(7) + Unit + } + is WebviewBundleException.CoreCancelled -> { + buf.putInt(8) + Unit + } + is WebviewBundleException.CoreTimeout -> { + buf.putInt(9) + Unit + } + is WebviewBundleException.CoreInvalidMagicNum -> { + buf.putInt(10) + Unit + } + is WebviewBundleException.CoreInvalidVersion -> { + buf.putInt(11) + Unit + } + is WebviewBundleException.CoreInvalidHeaderChecksum -> { + buf.putInt(12) + Unit + } + is WebviewBundleException.CoreInvalidIndexChecksum -> { + buf.putInt(13) + Unit + } + is WebviewBundleException.CoreChecksumMismatch -> { + buf.putInt(14) + Unit + } + is WebviewBundleException.CoreBundleNotFound -> { + buf.putInt(15) + Unit + } + is WebviewBundleException.CoreInvalidFilepath -> { + buf.putInt(16) + Unit + } + is WebviewBundleException.CoreSerdeJson -> { + buf.putInt(17) + Unit + } + is WebviewBundleException.CoreCannotResolveProxyServer -> { + buf.putInt(18) + Unit + } + is WebviewBundleException.CoreHttpClient -> { + buf.putInt(19) + Unit + } + is WebviewBundleException.CoreRemoteHttp -> { + buf.putInt(20) + Unit + } + is WebviewBundleException.CoreBadRemoteResponse -> { + buf.putInt(21) + Unit + } + is WebviewBundleException.CoreInvalidRemoteConfig -> { + buf.putInt(22) + Unit + } + is WebviewBundleException.CoreInvalidUpdaterConfig -> { + buf.putInt(23) + Unit + } + is WebviewBundleException.CoreInvalidIntegrity -> { + buf.putInt(24) + Unit + } + is WebviewBundleException.CoreIntegrityRequired -> { + buf.putInt(25) + Unit + } + is WebviewBundleException.CoreIntegrityVerifyFailed -> { + buf.putInt(26) + Unit + } + is WebviewBundleException.CoreInvalidSignature -> { + buf.putInt(27) + Unit + } + is WebviewBundleException.CoreInvalidSignatureKey -> { + buf.putInt(28) + Unit + } + is WebviewBundleException.CoreExpectSignatureNotFound -> { + buf.putInt(29) + Unit + } + is WebviewBundleException.CoreSignatureVerifyFailed -> { + buf.putInt(30) + Unit + } + is WebviewBundleException.CoreGeneric -> { + buf.putInt(31) + Unit + } + is WebviewBundleException.BindingInvalidHeaderName -> { + buf.putInt(32) + Unit + } + is WebviewBundleException.BindingInvalidHeaderValue -> { + buf.putInt(33) + Unit + } + is WebviewBundleException.BindingInvalidSignatureOptions -> { + buf.putInt(34) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } - +} - companion object -} /** * @suppress */ -public object FfiConverterTypeIntegrityAlgorithm: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - IntegrityAlgorithm.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) +public object FfiConverterOptionalUInt: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.UInt? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterUInt.read(buf) } - override fun allocationSize(value: IntegrityAlgorithm) = 4UL + override fun allocationSize(value: kotlin.UInt?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterUInt.allocationSize(value) + } + } - override fun write(value: IntegrityAlgorithm, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) + override fun write(value: kotlin.UInt?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterUInt.write(value, buf) + } } } - -/** - * How a bundle's integrity metadata is treated when the integrity check runs. - * - * - `Strict`: integrity metadata is required; a bundle without it fails the check. - * - `Optional`: integrity metadata is checked when present and tolerated when missing. - * - `Off`: the integrity check is disabled. - */ - -enum class IntegrityPolicy { - - STRICT, - OPTIONAL, - OFF; - - - - - companion object -} - - /** * @suppress */ -public object FfiConverterTypeIntegrityPolicy: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - IntegrityPolicy.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) +public object FfiConverterOptionalULong: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.ULong? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterULong.read(buf) } - override fun allocationSize(value: IntegrityPolicy) = 4UL + override fun allocationSize(value: kotlin.ULong?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterULong.allocationSize(value) + } + } - override fun write(value: IntegrityPolicy, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) + override fun write(value: kotlin.ULong?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterULong.write(value, buf) + } } } - /** - * How the file path in the bundle is resolved from the request uri. + * @suppress */ +public object FfiConverterOptionalBoolean: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.Boolean? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterBoolean.read(buf) + } -enum class PathResolver { - - /** - * Use the uri path as-is (only percent-decoded). - */ - EXACT, - /** - * Directory index: `/` -> `/index.html` and `/about` -> `/about/index.html`. - */ - DIRECTORY_INDEX, - /** - * `.html` extension: `/` -> `/index.html` and `/about` -> `/about.html`. - */ - HTML_EXTENSION; + override fun allocationSize(value: kotlin.Boolean?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterBoolean.allocationSize(value) + } + } - + override fun write(value: kotlin.Boolean?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterBoolean.write(value, buf) + } + } +} - companion object -} /** * @suppress */ -public object FfiConverterTypePathResolver: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - PathResolver.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) +public object FfiConverterOptionalString: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.String? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterString.read(buf) } - override fun allocationSize(value: PathResolver) = 4UL + override fun allocationSize(value: kotlin.String?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterString.allocationSize(value) + } + } - override fun write(value: PathResolver, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) + override fun write(value: kotlin.String?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterString.write(value, buf) + } } } - /** - * Digital signature algorithm used to verify bundle authenticity. + * @suppress */ +public object FfiConverterOptionalByteArray: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): kotlin.ByteArray? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterByteArray.read(buf) + } -enum class SignatureAlgorithm { - - ECDSA_SECP256R1, - ECDSA_SECP384R1, - ED25519, - RSA_PKCS1_V15, - RSA_PSS; + override fun allocationSize(value: kotlin.ByteArray?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterByteArray.allocationSize(value) + } + } - + override fun write(value: kotlin.ByteArray?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterByteArray.write(value, buf) + } + } +} - companion object -} /** * @suppress */ -public object FfiConverterTypeSignatureAlgorithm: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - SignatureAlgorithm.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) +public object FfiConverterOptionalTypeCancellation: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Cancellation? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeCancellation.read(buf) } - override fun allocationSize(value: SignatureAlgorithm) = 4UL + override fun allocationSize(value: Cancellation?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeCancellation.allocationSize(value) + } + } - override fun write(value: SignatureAlgorithm, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) + override fun write(value: Cancellation?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeCancellation.write(value, buf) + } } } - /** - * How a bundle's signature is verified: with a declarative public key, or a custom function. + * @suppress */ -sealed class SignatureVerification: Disposable { - - /** - * Verify with a public key of a known algorithm. - */ - data class Key( - val `options`: dev.wvb.SignatureVerifierOptions) : SignatureVerification() - - { - - - companion object +public object FfiConverterOptionalTypeRemoteOnDownload: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RemoteOnDownload? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeRemoteOnDownload.read(buf) } - - /** - * Verify with a custom function over the integrity string. - */ - data class Custom( - val `verify`: dev.wvb.SignatureVerify) : SignatureVerification() - - { - - companion object + override fun allocationSize(value: RemoteOnDownload?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeRemoteOnDownload.allocationSize(value) + } } - - - @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here - override fun destroy() { - when(this) { - is SignatureVerification.Key -> { - - Disposable.destroy( - this.`options` - ) - - } - is SignatureVerification.Custom -> { - - Disposable.destroy( - this.`verify` - ) - - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + override fun write(value: RemoteOnDownload?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeRemoteOnDownload.write(value, buf) + } } - +} - - - companion object -} /** * @suppress */ -public object FfiConverterTypeSignatureVerification : FfiConverterRustBuffer{ - override fun read(buf: ByteBuffer): SignatureVerification { - return when(buf.getInt()) { - 1 -> SignatureVerification.Key( - FfiConverterTypeSignatureVerifierOptions.read(buf), - ) - 2 -> SignatureVerification.Custom( - FfiConverterTypeSignatureVerify.read(buf), - ) - else -> throw RuntimeException("invalid enum value, something is very wrong!!") +public object FfiConverterOptionalTypeBuildHeaderOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BuildHeaderOptions? { + if (buf.get().toInt() == 0) { + return null } + return FfiConverterTypeBuildHeaderOptions.read(buf) } - override fun allocationSize(value: SignatureVerification) = when(value) { - is SignatureVerification.Key -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeSignatureVerifierOptions.allocationSize(value.`options`) - ) - } - is SignatureVerification.Custom -> { - // Add the size for the Int that specifies the variant plus the size needed for all fields - ( - 4UL - + FfiConverterTypeSignatureVerify.allocationSize(value.`verify`) - ) + override fun allocationSize(value: BuildHeaderOptions?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeBuildHeaderOptions.allocationSize(value) } } - override fun write(value: SignatureVerification, buf: ByteBuffer) { - when(value) { - is SignatureVerification.Key -> { - buf.putInt(1) - FfiConverterTypeSignatureVerifierOptions.write(value.`options`, buf) - Unit - } - is SignatureVerification.Custom -> { - buf.putInt(2) - FfiConverterTypeSignatureVerify.write(value.`verify`, buf) - Unit - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + override fun write(value: BuildHeaderOptions?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeBuildHeaderOptions.write(value, buf) + } } } - /** - * Encoding format of the public key provided in [`SignatureVerifyingKey`]. - * - * Not all combinations of algorithm + format are valid; unsupported pairs - * return [`Error::BindingInvalidSignatureOptions`] at construction time. + * @suppress */ +public object FfiConverterOptionalTypeBuildIndexOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BuildIndexOptions? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeBuildIndexOptions.read(buf) + } -enum class VerifyingKeyFormat { - - SPKI_DER, - SPKI_PEM, - PKCS1_DER, - PKCS1_PEM, - SEC1, - RAW; + override fun allocationSize(value: BuildIndexOptions?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeBuildIndexOptions.allocationSize(value) + } + } - + override fun write(value: BuildIndexOptions?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeBuildIndexOptions.write(value, buf) + } + } +} - companion object -} /** * @suppress */ -public object FfiConverterTypeVerifyingKeyFormat: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - VerifyingKeyFormat.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) +public object FfiConverterOptionalTypeBuildOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BuildOptions? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeBuildOptions.read(buf) } - override fun allocationSize(value: VerifyingKeyFormat) = 4UL + override fun allocationSize(value: BuildOptions?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeBuildOptions.allocationSize(value) + } + } - override fun write(value: VerifyingKeyFormat, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) + override fun write(value: BuildOptions?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeBuildOptions.write(value, buf) + } } } - /** - * Bundle format version. Currently only `V1` is defined. + * @suppress */ +public object FfiConverterOptionalTypeBundleProtocolOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BundleProtocolOptions? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeBundleProtocolOptions.read(buf) + } -enum class Version { - - V1; + override fun allocationSize(value: BundleProtocolOptions?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeBundleProtocolOptions.allocationSize(value) + } + } - + override fun write(value: BundleProtocolOptions?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeBundleProtocolOptions.write(value, buf) + } + } +} - companion object -} /** * @suppress */ -public object FfiConverterTypeVersion: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer) = try { - Version.values()[buf.getInt() - 1] - } catch (e: IndexOutOfBoundsException) { - throw RuntimeException("invalid enum value, something is very wrong!!", e) +public object FfiConverterOptionalTypeBundleSourceVersion: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BundleSourceVersion? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeBundleSourceVersion.read(buf) } - override fun allocationSize(value: Version) = 4UL + override fun allocationSize(value: BundleSourceVersion?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeBundleSourceVersion.allocationSize(value) + } + } - override fun write(value: Version, buf: ByteBuffer) { - buf.putInt(value.ordinal + 1) + override fun write(value: BundleSourceVersion?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeBundleSourceVersion.write(value, buf) + } } } - - - /** - * WebviewBundle Error. + * @suppress */ -sealed class WebviewBundleException(message: String): kotlin.Exception(message) { - - class CoreIo(message: String) : WebviewBundleException(message) - - class CoreCompress(message: String) : WebviewBundleException(message) - - class CoreDecompress(message: String) : WebviewBundleException(message) - - class CoreEncode(message: String) : WebviewBundleException(message) - - class CoreDecode(message: String) : WebviewBundleException(message) - - class CoreHttp(message: String) : WebviewBundleException(message) - - class CoreInvalidMagicNum(message: String) : WebviewBundleException(message) - - class CoreInvalidVersion(message: String) : WebviewBundleException(message) - - class CoreInvalidHeaderChecksum(message: String) : WebviewBundleException(message) - - class CoreInvalidIndexChecksum(message: String) : WebviewBundleException(message) - - class CoreChecksumMismatch(message: String) : WebviewBundleException(message) - - class CoreBundleNotFound(message: String) : WebviewBundleException(message) - - class CoreBundleEntryNotExists(message: String) : WebviewBundleException(message) - - class CoreBundleCannotBeRemoved(message: String) : WebviewBundleException(message) - - class CoreInvalidFilepath(message: String) : WebviewBundleException(message) - - class CoreSerdeJson(message: String) : WebviewBundleException(message) - - class CoreCannotResolveProxyServer(message: String) : WebviewBundleException(message) - - class CoreReqwest(message: String) : WebviewBundleException(message) - - class CoreInvalidRemoteUrl(message: String) : WebviewBundleException(message) - - class CoreInvalidRemoteBundle(message: String) : WebviewBundleException(message) - - class CoreRemoteBundleNotFound(message: String) : WebviewBundleException(message) - - class CoreRemoteForbidden(message: String) : WebviewBundleException(message) - - class CoreRemoteHttp(message: String) : WebviewBundleException(message) - - class CoreInvalidRemoteConfig(message: String) : WebviewBundleException(message) - - class CoreInvalidIntegrity(message: String) : WebviewBundleException(message) - - class CoreIntegrityRequired(message: String) : WebviewBundleException(message) - - class CoreIntegrityVerifyFailed(message: String) : WebviewBundleException(message) - - class CoreInvalidSignature(message: String) : WebviewBundleException(message) - - class CoreInvalidSigningKey(message: String) : WebviewBundleException(message) - - class CoreSignatureSignFailed(message: String) : WebviewBundleException(message) - - class CoreInvalidVerifyingKey(message: String) : WebviewBundleException(message) - - class CoreSignatureNotExists(message: String) : WebviewBundleException(message) - - class CoreSignatureVerifyFailed(message: String) : WebviewBundleException(message) - - class CoreGeneric(message: String) : WebviewBundleException(message) - - /** - * Invalid HTTP header name. - */ - class BindingInvalidHeaderName(message: String) : WebviewBundleException(message) - - /** - * Invalid HTTP header value. - */ - class BindingInvalidHeaderValue(message: String) : WebviewBundleException(message) - - /** - * The `SignatureVerifierOptions` passed across the boundary could not be turned into a - * verifier (unsupported algorithm/format pairing, or a key of the wrong shape). - */ - class BindingInvalidSignatureOptions(message: String) : WebviewBundleException(message) - +public object FfiConverterOptionalTypeChecksumReadOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChecksumReadOptions? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeChecksumReadOptions.read(buf) + } + + override fun allocationSize(value: ChecksumReadOptions?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeChecksumReadOptions.allocationSize(value) + } + } - companion object ErrorHandler : UniffiRustCallStatusErrorHandler { - override fun lift(error_buf: RustBuffer.ByValue): WebviewBundleException = FfiConverterTypeWebviewBundleError.lift(error_buf) + override fun write(value: ChecksumReadOptions?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeChecksumReadOptions.write(value, buf) + } } } + + + /** * @suppress */ -public object FfiConverterTypeWebviewBundleError : FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): WebviewBundleException { - - return when(buf.getInt()) { - 1 -> WebviewBundleException.CoreIo(FfiConverterString.read(buf)) - 2 -> WebviewBundleException.CoreCompress(FfiConverterString.read(buf)) - 3 -> WebviewBundleException.CoreDecompress(FfiConverterString.read(buf)) - 4 -> WebviewBundleException.CoreEncode(FfiConverterString.read(buf)) - 5 -> WebviewBundleException.CoreDecode(FfiConverterString.read(buf)) - 6 -> WebviewBundleException.CoreHttp(FfiConverterString.read(buf)) - 7 -> WebviewBundleException.CoreInvalidMagicNum(FfiConverterString.read(buf)) - 8 -> WebviewBundleException.CoreInvalidVersion(FfiConverterString.read(buf)) - 9 -> WebviewBundleException.CoreInvalidHeaderChecksum(FfiConverterString.read(buf)) - 10 -> WebviewBundleException.CoreInvalidIndexChecksum(FfiConverterString.read(buf)) - 11 -> WebviewBundleException.CoreChecksumMismatch(FfiConverterString.read(buf)) - 12 -> WebviewBundleException.CoreBundleNotFound(FfiConverterString.read(buf)) - 13 -> WebviewBundleException.CoreBundleEntryNotExists(FfiConverterString.read(buf)) - 14 -> WebviewBundleException.CoreBundleCannotBeRemoved(FfiConverterString.read(buf)) - 15 -> WebviewBundleException.CoreInvalidFilepath(FfiConverterString.read(buf)) - 16 -> WebviewBundleException.CoreSerdeJson(FfiConverterString.read(buf)) - 17 -> WebviewBundleException.CoreCannotResolveProxyServer(FfiConverterString.read(buf)) - 18 -> WebviewBundleException.CoreReqwest(FfiConverterString.read(buf)) - 19 -> WebviewBundleException.CoreInvalidRemoteUrl(FfiConverterString.read(buf)) - 20 -> WebviewBundleException.CoreInvalidRemoteBundle(FfiConverterString.read(buf)) - 21 -> WebviewBundleException.CoreRemoteBundleNotFound(FfiConverterString.read(buf)) - 22 -> WebviewBundleException.CoreRemoteForbidden(FfiConverterString.read(buf)) - 23 -> WebviewBundleException.CoreRemoteHttp(FfiConverterString.read(buf)) - 24 -> WebviewBundleException.CoreInvalidRemoteConfig(FfiConverterString.read(buf)) - 25 -> WebviewBundleException.CoreInvalidIntegrity(FfiConverterString.read(buf)) - 26 -> WebviewBundleException.CoreIntegrityRequired(FfiConverterString.read(buf)) - 27 -> WebviewBundleException.CoreIntegrityVerifyFailed(FfiConverterString.read(buf)) - 28 -> WebviewBundleException.CoreInvalidSignature(FfiConverterString.read(buf)) - 29 -> WebviewBundleException.CoreInvalidSigningKey(FfiConverterString.read(buf)) - 30 -> WebviewBundleException.CoreSignatureSignFailed(FfiConverterString.read(buf)) - 31 -> WebviewBundleException.CoreInvalidVerifyingKey(FfiConverterString.read(buf)) - 32 -> WebviewBundleException.CoreSignatureNotExists(FfiConverterString.read(buf)) - 33 -> WebviewBundleException.CoreSignatureVerifyFailed(FfiConverterString.read(buf)) - 34 -> WebviewBundleException.CoreGeneric(FfiConverterString.read(buf)) - 35 -> WebviewBundleException.BindingInvalidHeaderName(FfiConverterString.read(buf)) - 36 -> WebviewBundleException.BindingInvalidHeaderValue(FfiConverterString.read(buf)) - 37 -> WebviewBundleException.BindingInvalidSignatureOptions(FfiConverterString.read(buf)) - else -> throw RuntimeException("invalid error enum value, something is very wrong!!") +public object FfiConverterOptionalTypeChecksumWriteOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ChecksumWriteOptions? { + if (buf.get().toInt() == 0) { + return null } - + return FfiConverterTypeChecksumWriteOptions.read(buf) } - override fun allocationSize(value: WebviewBundleException): ULong { - return 4UL + override fun allocationSize(value: ChecksumWriteOptions?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeChecksumWriteOptions.allocationSize(value) + } } - override fun write(value: WebviewBundleException, buf: ByteBuffer) { - when(value) { - is WebviewBundleException.CoreIo -> { - buf.putInt(1) - Unit - } - is WebviewBundleException.CoreCompress -> { - buf.putInt(2) - Unit - } - is WebviewBundleException.CoreDecompress -> { - buf.putInt(3) - Unit - } - is WebviewBundleException.CoreEncode -> { - buf.putInt(4) - Unit - } - is WebviewBundleException.CoreDecode -> { - buf.putInt(5) - Unit - } - is WebviewBundleException.CoreHttp -> { - buf.putInt(6) - Unit - } - is WebviewBundleException.CoreInvalidMagicNum -> { - buf.putInt(7) - Unit - } - is WebviewBundleException.CoreInvalidVersion -> { - buf.putInt(8) - Unit - } - is WebviewBundleException.CoreInvalidHeaderChecksum -> { - buf.putInt(9) - Unit - } - is WebviewBundleException.CoreInvalidIndexChecksum -> { - buf.putInt(10) - Unit - } - is WebviewBundleException.CoreChecksumMismatch -> { - buf.putInt(11) - Unit - } - is WebviewBundleException.CoreBundleNotFound -> { - buf.putInt(12) - Unit - } - is WebviewBundleException.CoreBundleEntryNotExists -> { - buf.putInt(13) - Unit - } - is WebviewBundleException.CoreBundleCannotBeRemoved -> { - buf.putInt(14) - Unit - } - is WebviewBundleException.CoreInvalidFilepath -> { - buf.putInt(15) - Unit - } - is WebviewBundleException.CoreSerdeJson -> { - buf.putInt(16) - Unit - } - is WebviewBundleException.CoreCannotResolveProxyServer -> { - buf.putInt(17) - Unit - } - is WebviewBundleException.CoreReqwest -> { - buf.putInt(18) - Unit - } - is WebviewBundleException.CoreInvalidRemoteUrl -> { - buf.putInt(19) - Unit - } - is WebviewBundleException.CoreInvalidRemoteBundle -> { - buf.putInt(20) - Unit - } - is WebviewBundleException.CoreRemoteBundleNotFound -> { - buf.putInt(21) - Unit - } - is WebviewBundleException.CoreRemoteForbidden -> { - buf.putInt(22) - Unit - } - is WebviewBundleException.CoreRemoteHttp -> { - buf.putInt(23) - Unit - } - is WebviewBundleException.CoreInvalidRemoteConfig -> { - buf.putInt(24) - Unit - } - is WebviewBundleException.CoreInvalidIntegrity -> { - buf.putInt(25) - Unit - } - is WebviewBundleException.CoreIntegrityRequired -> { - buf.putInt(26) - Unit - } - is WebviewBundleException.CoreIntegrityVerifyFailed -> { - buf.putInt(27) - Unit - } - is WebviewBundleException.CoreInvalidSignature -> { - buf.putInt(28) - Unit - } - is WebviewBundleException.CoreInvalidSigningKey -> { - buf.putInt(29) - Unit - } - is WebviewBundleException.CoreSignatureSignFailed -> { - buf.putInt(30) - Unit - } - is WebviewBundleException.CoreInvalidVerifyingKey -> { - buf.putInt(31) - Unit - } - is WebviewBundleException.CoreSignatureNotExists -> { - buf.putInt(32) - Unit - } - is WebviewBundleException.CoreSignatureVerifyFailed -> { - buf.putInt(33) - Unit - } - is WebviewBundleException.CoreGeneric -> { - buf.putInt(34) - Unit - } - is WebviewBundleException.BindingInvalidHeaderName -> { - buf.putInt(35) - Unit - } - is WebviewBundleException.BindingInvalidHeaderValue -> { - buf.putInt(36) - Unit - } - is WebviewBundleException.BindingInvalidSignatureOptions -> { - buf.putInt(37) - Unit - } - }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + override fun write(value: ChecksumWriteOptions?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeChecksumWriteOptions.write(value, buf) + } + } +} + + + + +/** + * @suppress + */ +public object FfiConverterOptionalTypeDataReadOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): DataReadOptions? { + if (buf.get().toInt() == 0) { + return null + } + return FfiConverterTypeDataReadOptions.read(buf) + } + + override fun allocationSize(value: DataReadOptions?): ULong { + if (value == null) { + return 1UL + } else { + return 1UL + FfiConverterTypeDataReadOptions.allocationSize(value) + } } + override fun write(value: DataReadOptions?, buf: ByteBuffer) { + if (value == null) { + buf.put(0) + } else { + buf.put(1) + FfiConverterTypeDataReadOptions.write(value, buf) + } + } } @@ -10381,28 +12173,28 @@ public object FfiConverterTypeWebviewBundleError : FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): kotlin.UInt? { +public object FfiConverterOptionalTypeHeaderReadOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): HeaderReadOptions? { if (buf.get().toInt() == 0) { return null } - return FfiConverterUInt.read(buf) + return FfiConverterTypeHeaderReadOptions.read(buf) } - override fun allocationSize(value: kotlin.UInt?): ULong { + override fun allocationSize(value: HeaderReadOptions?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterUInt.allocationSize(value) + return 1UL + FfiConverterTypeHeaderReadOptions.allocationSize(value) } } - override fun write(value: kotlin.UInt?, buf: ByteBuffer) { + override fun write(value: HeaderReadOptions?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterUInt.write(value, buf) + FfiConverterTypeHeaderReadOptions.write(value, buf) } } } @@ -10413,28 +12205,28 @@ public object FfiConverterOptionalUInt: FfiConverterRustBuffer { /** * @suppress */ -public object FfiConverterOptionalULong: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): kotlin.ULong? { +public object FfiConverterOptionalTypeHttpOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): HttpOptions? { if (buf.get().toInt() == 0) { return null } - return FfiConverterULong.read(buf) + return FfiConverterTypeHttpOptions.read(buf) } - override fun allocationSize(value: kotlin.ULong?): ULong { + override fun allocationSize(value: HttpOptions?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterULong.allocationSize(value) + return 1UL + FfiConverterTypeHttpOptions.allocationSize(value) } } - override fun write(value: kotlin.ULong?, buf: ByteBuffer) { + override fun write(value: HttpOptions?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterULong.write(value, buf) + FfiConverterTypeHttpOptions.write(value, buf) } } } @@ -10445,28 +12237,28 @@ public object FfiConverterOptionalULong: FfiConverterRustBuffer { /** * @suppress */ -public object FfiConverterOptionalBoolean: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): kotlin.Boolean? { +public object FfiConverterOptionalTypeIndexEntry: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): IndexEntry? { if (buf.get().toInt() == 0) { return null } - return FfiConverterBoolean.read(buf) + return FfiConverterTypeIndexEntry.read(buf) } - override fun allocationSize(value: kotlin.Boolean?): ULong { + override fun allocationSize(value: IndexEntry?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterBoolean.allocationSize(value) + return 1UL + FfiConverterTypeIndexEntry.allocationSize(value) } } - override fun write(value: kotlin.Boolean?, buf: ByteBuffer) { + override fun write(value: IndexEntry?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterBoolean.write(value, buf) + FfiConverterTypeIndexEntry.write(value, buf) } } } @@ -10477,28 +12269,28 @@ public object FfiConverterOptionalBoolean: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): kotlin.String? { +public object FfiConverterOptionalTypeIndexReadOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): IndexReadOptions? { if (buf.get().toInt() == 0) { return null } - return FfiConverterString.read(buf) + return FfiConverterTypeIndexReadOptions.read(buf) } - override fun allocationSize(value: kotlin.String?): ULong { + override fun allocationSize(value: IndexReadOptions?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterString.allocationSize(value) + return 1UL + FfiConverterTypeIndexReadOptions.allocationSize(value) } } - override fun write(value: kotlin.String?, buf: ByteBuffer) { + override fun write(value: IndexReadOptions?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterString.write(value, buf) + FfiConverterTypeIndexReadOptions.write(value, buf) } } } @@ -10509,28 +12301,28 @@ public object FfiConverterOptionalString: FfiConverterRustBuffer /** * @suppress */ -public object FfiConverterOptionalByteArray: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): kotlin.ByteArray? { +public object FfiConverterOptionalTypeManifestVersionData: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ManifestVersionData? { if (buf.get().toInt() == 0) { return null } - return FfiConverterByteArray.read(buf) + return FfiConverterTypeManifestVersionData.read(buf) } - override fun allocationSize(value: kotlin.ByteArray?): ULong { + override fun allocationSize(value: ManifestVersionData?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterByteArray.allocationSize(value) + return 1UL + FfiConverterTypeManifestVersionData.allocationSize(value) } } - override fun write(value: kotlin.ByteArray?, buf: ByteBuffer) { + override fun write(value: ManifestVersionData?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterByteArray.write(value, buf) + FfiConverterTypeManifestVersionData.write(value, buf) } } } @@ -10541,28 +12333,28 @@ public object FfiConverterOptionalByteArray: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): IntegrityCheck? { +public object FfiConverterOptionalTypeRemoteGetUpdateOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RemoteGetUpdateOptions? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeIntegrityCheck.read(buf) + return FfiConverterTypeRemoteGetUpdateOptions.read(buf) } - override fun allocationSize(value: IntegrityCheck?): ULong { + override fun allocationSize(value: RemoteGetUpdateOptions?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeIntegrityCheck.allocationSize(value) + return 1UL + FfiConverterTypeRemoteGetUpdateOptions.allocationSize(value) } } - override fun write(value: IntegrityCheck?, buf: ByteBuffer) { + override fun write(value: RemoteGetUpdateOptions?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeIntegrityCheck.write(value, buf) + FfiConverterTypeRemoteGetUpdateOptions.write(value, buf) } } } @@ -10573,28 +12365,28 @@ public object FfiConverterOptionalTypeIntegrityCheck: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): RemoteOnDownload? { +public object FfiConverterOptionalTypeRemoteOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RemoteOptions? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeRemoteOnDownload.read(buf) + return FfiConverterTypeRemoteOptions.read(buf) } - override fun allocationSize(value: RemoteOnDownload?): ULong { + override fun allocationSize(value: RemoteOptions?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeRemoteOnDownload.allocationSize(value) + return 1UL + FfiConverterTypeRemoteOptions.allocationSize(value) } } - override fun write(value: RemoteOnDownload?, buf: ByteBuffer) { + override fun write(value: RemoteOptions?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeRemoteOnDownload.write(value, buf) + FfiConverterTypeRemoteOptions.write(value, buf) } } } @@ -10605,28 +12397,28 @@ public object FfiConverterOptionalTypeRemoteOnDownload: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BuildHeaderOptions? { +public object FfiConverterOptionalTypeRemoteUpdateResponse: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): RemoteUpdateResponse? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeBuildHeaderOptions.read(buf) + return FfiConverterTypeRemoteUpdateResponse.read(buf) } - override fun allocationSize(value: BuildHeaderOptions?): ULong { + override fun allocationSize(value: RemoteUpdateResponse?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeBuildHeaderOptions.allocationSize(value) + return 1UL + FfiConverterTypeRemoteUpdateResponse.allocationSize(value) } } - override fun write(value: BuildHeaderOptions?, buf: ByteBuffer) { + override fun write(value: RemoteUpdateResponse?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeBuildHeaderOptions.write(value, buf) + FfiConverterTypeRemoteUpdateResponse.write(value, buf) } } } @@ -10637,28 +12429,28 @@ public object FfiConverterOptionalTypeBuildHeaderOptions: FfiConverterRustBuffer /** * @suppress */ -public object FfiConverterOptionalTypeBuildIndexOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BuildIndexOptions? { +public object FfiConverterOptionalTypeSignatureVerifyKey: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): SignatureVerifyKey? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeBuildIndexOptions.read(buf) + return FfiConverterTypeSignatureVerifyKey.read(buf) } - override fun allocationSize(value: BuildIndexOptions?): ULong { + override fun allocationSize(value: SignatureVerifyKey?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeBuildIndexOptions.allocationSize(value) + return 1UL + FfiConverterTypeSignatureVerifyKey.allocationSize(value) } } - override fun write(value: BuildIndexOptions?, buf: ByteBuffer) { + override fun write(value: SignatureVerifyKey?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeBuildIndexOptions.write(value, buf) + FfiConverterTypeSignatureVerifyKey.write(value, buf) } } } @@ -10669,28 +12461,28 @@ public object FfiConverterOptionalTypeBuildIndexOptions: FfiConverterRustBuffer< /** * @suppress */ -public object FfiConverterOptionalTypeBuildOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BuildOptions? { +public object FfiConverterOptionalTypeSourceIntegrityOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): SourceIntegrityOptions? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeBuildOptions.read(buf) + return FfiConverterTypeSourceIntegrityOptions.read(buf) } - override fun allocationSize(value: BuildOptions?): ULong { + override fun allocationSize(value: SourceIntegrityOptions?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeBuildOptions.allocationSize(value) + return 1UL + FfiConverterTypeSourceIntegrityOptions.allocationSize(value) } } - override fun write(value: BuildOptions?, buf: ByteBuffer) { + override fun write(value: SourceIntegrityOptions?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeBuildOptions.write(value, buf) + FfiConverterTypeSourceIntegrityOptions.write(value, buf) } } } @@ -10701,28 +12493,28 @@ public object FfiConverterOptionalTypeBuildOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleManifestMetadata? { +public object FfiConverterOptionalTypeUpdate: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Update? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeBundleManifestMetadata.read(buf) + return FfiConverterTypeUpdate.read(buf) } - override fun allocationSize(value: BundleManifestMetadata?): ULong { + override fun allocationSize(value: Update?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeBundleManifestMetadata.allocationSize(value) + return 1UL + FfiConverterTypeUpdate.allocationSize(value) } } - override fun write(value: BundleManifestMetadata?, buf: ByteBuffer) { + override fun write(value: Update?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeBundleManifestMetadata.write(value, buf) + FfiConverterTypeUpdate.write(value, buf) } } } @@ -10733,28 +12525,28 @@ public object FfiConverterOptionalTypeBundleManifestMetadata: FfiConverterRustBu /** * @suppress */ -public object FfiConverterOptionalTypeBundleProtocolOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleProtocolOptions? { +public object FfiConverterOptionalTypeUpdateSignature: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdateSignature? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeBundleProtocolOptions.read(buf) + return FfiConverterTypeUpdateSignature.read(buf) } - override fun allocationSize(value: BundleProtocolOptions?): ULong { + override fun allocationSize(value: UpdateSignature?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeBundleProtocolOptions.allocationSize(value) + return 1UL + FfiConverterTypeUpdateSignature.allocationSize(value) } } - override fun write(value: BundleProtocolOptions?, buf: ByteBuffer) { + override fun write(value: UpdateSignature?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeBundleProtocolOptions.write(value, buf) + FfiConverterTypeUpdateSignature.write(value, buf) } } } @@ -10765,28 +12557,28 @@ public object FfiConverterOptionalTypeBundleProtocolOptions: FfiConverterRustBuf /** * @suppress */ -public object FfiConverterOptionalTypeBundleSourceIntegrityOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleSourceIntegrityOptions? { +public object FfiConverterOptionalTypeUpdaterDownloadOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterDownloadOptions? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeBundleSourceIntegrityOptions.read(buf) + return FfiConverterTypeUpdaterDownloadOptions.read(buf) } - override fun allocationSize(value: BundleSourceIntegrityOptions?): ULong { + override fun allocationSize(value: UpdaterDownloadOptions?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeBundleSourceIntegrityOptions.allocationSize(value) + return 1UL + FfiConverterTypeUpdaterDownloadOptions.allocationSize(value) } } - override fun write(value: BundleSourceIntegrityOptions?, buf: ByteBuffer) { + override fun write(value: UpdaterDownloadOptions?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeBundleSourceIntegrityOptions.write(value, buf) + FfiConverterTypeUpdaterDownloadOptions.write(value, buf) } } } @@ -10797,28 +12589,28 @@ public object FfiConverterOptionalTypeBundleSourceIntegrityOptions: FfiConverter /** * @suppress */ -public object FfiConverterOptionalTypeBundleSourceSignatureOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleSourceSignatureOptions? { +public object FfiConverterOptionalTypeUpdaterGetUpdateOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterGetUpdateOptions? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeBundleSourceSignatureOptions.read(buf) + return FfiConverterTypeUpdaterGetUpdateOptions.read(buf) } - override fun allocationSize(value: BundleSourceSignatureOptions?): ULong { + override fun allocationSize(value: UpdaterGetUpdateOptions?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeBundleSourceSignatureOptions.allocationSize(value) + return 1UL + FfiConverterTypeUpdaterGetUpdateOptions.allocationSize(value) } } - override fun write(value: BundleSourceSignatureOptions?, buf: ByteBuffer) { + override fun write(value: UpdaterGetUpdateOptions?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeBundleSourceSignatureOptions.write(value, buf) + FfiConverterTypeUpdaterGetUpdateOptions.write(value, buf) } } } @@ -10829,28 +12621,28 @@ public object FfiConverterOptionalTypeBundleSourceSignatureOptions: FfiConverter /** * @suppress */ -public object FfiConverterOptionalTypeBundleSourceVersion: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleSourceVersion? { +public object FfiConverterOptionalTypeUpdaterIntegrityOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterIntegrityOptions? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeBundleSourceVersion.read(buf) + return FfiConverterTypeUpdaterIntegrityOptions.read(buf) } - override fun allocationSize(value: BundleSourceVersion?): ULong { + override fun allocationSize(value: UpdaterIntegrityOptions?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeBundleSourceVersion.allocationSize(value) + return 1UL + FfiConverterTypeUpdaterIntegrityOptions.allocationSize(value) } } - override fun write(value: BundleSourceVersion?, buf: ByteBuffer) { + override fun write(value: UpdaterIntegrityOptions?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeBundleSourceVersion.write(value, buf) + FfiConverterTypeUpdaterIntegrityOptions.write(value, buf) } } } @@ -10861,28 +12653,28 @@ public object FfiConverterOptionalTypeBundleSourceVersion: FfiConverterRustBuffe /** * @suppress */ -public object FfiConverterOptionalTypeChecksumReadOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ChecksumReadOptions? { +public object FfiConverterOptionalTypeUpdaterOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterOptions? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeChecksumReadOptions.read(buf) + return FfiConverterTypeUpdaterOptions.read(buf) } - override fun allocationSize(value: ChecksumReadOptions?): ULong { + override fun allocationSize(value: UpdaterOptions?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeChecksumReadOptions.allocationSize(value) + return 1UL + FfiConverterTypeUpdaterOptions.allocationSize(value) } } - override fun write(value: ChecksumReadOptions?, buf: ByteBuffer) { + override fun write(value: UpdaterOptions?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeChecksumReadOptions.write(value, buf) + FfiConverterTypeUpdaterOptions.write(value, buf) } } } @@ -10893,28 +12685,28 @@ public object FfiConverterOptionalTypeChecksumReadOptions: FfiConverterRustBuffe /** * @suppress */ -public object FfiConverterOptionalTypeChecksumWriteOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): ChecksumWriteOptions? { +public object FfiConverterOptionalTypeUpdaterSignatureOptions: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): UpdaterSignatureOptions? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeChecksumWriteOptions.read(buf) + return FfiConverterTypeUpdaterSignatureOptions.read(buf) } - override fun allocationSize(value: ChecksumWriteOptions?): ULong { + override fun allocationSize(value: UpdaterSignatureOptions?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeChecksumWriteOptions.allocationSize(value) + return 1UL + FfiConverterTypeUpdaterSignatureOptions.allocationSize(value) } } - override fun write(value: ChecksumWriteOptions?, buf: ByteBuffer) { + override fun write(value: UpdaterSignatureOptions?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeChecksumWriteOptions.write(value, buf) + FfiConverterTypeUpdaterSignatureOptions.write(value, buf) } } } @@ -10925,28 +12717,28 @@ public object FfiConverterOptionalTypeChecksumWriteOptions: FfiConverterRustBuff /** * @suppress */ -public object FfiConverterOptionalTypeDataReadOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): DataReadOptions? { +public object FfiConverterOptionalTypeBundleResolver: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): BundleResolver? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeDataReadOptions.read(buf) + return FfiConverterTypeBundleResolver.read(buf) } - override fun allocationSize(value: DataReadOptions?): ULong { + override fun allocationSize(value: BundleResolver?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeDataReadOptions.allocationSize(value) + return 1UL + FfiConverterTypeBundleResolver.allocationSize(value) } } - override fun write(value: DataReadOptions?, buf: ByteBuffer) { + override fun write(value: BundleResolver?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeDataReadOptions.write(value, buf) + FfiConverterTypeBundleResolver.write(value, buf) } } } @@ -10957,28 +12749,28 @@ public object FfiConverterOptionalTypeDataReadOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): HeaderReadOptions? { +public object FfiConverterOptionalTypeHostnameSegment: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): HostnameSegment? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeHeaderReadOptions.read(buf) + return FfiConverterTypeHostnameSegment.read(buf) } - override fun allocationSize(value: HeaderReadOptions?): ULong { + override fun allocationSize(value: HostnameSegment?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeHeaderReadOptions.allocationSize(value) + return 1UL + FfiConverterTypeHostnameSegment.allocationSize(value) } } - override fun write(value: HeaderReadOptions?, buf: ByteBuffer) { + override fun write(value: HostnameSegment?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeHeaderReadOptions.write(value, buf) + FfiConverterTypeHostnameSegment.write(value, buf) } } } @@ -10989,28 +12781,28 @@ public object FfiConverterOptionalTypeHeaderReadOptions: FfiConverterRustBuffer< /** * @suppress */ -public object FfiConverterOptionalTypeHttpOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): HttpOptions? { +public object FfiConverterOptionalTypeIntegrityAlgorithm: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): IntegrityAlgorithm? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeHttpOptions.read(buf) + return FfiConverterTypeIntegrityAlgorithm.read(buf) } - override fun allocationSize(value: HttpOptions?): ULong { + override fun allocationSize(value: IntegrityAlgorithm?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeHttpOptions.allocationSize(value) + return 1UL + FfiConverterTypeIntegrityAlgorithm.allocationSize(value) } } - override fun write(value: HttpOptions?, buf: ByteBuffer) { + override fun write(value: IntegrityAlgorithm?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeHttpOptions.write(value, buf) + FfiConverterTypeIntegrityAlgorithm.write(value, buf) } } } @@ -11021,28 +12813,28 @@ public object FfiConverterOptionalTypeHttpOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): IndexEntry? { +public object FfiConverterOptionalTypeIntegrityPolicy: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): IntegrityPolicy? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeIndexEntry.read(buf) + return FfiConverterTypeIntegrityPolicy.read(buf) } - override fun allocationSize(value: IndexEntry?): ULong { + override fun allocationSize(value: IntegrityPolicy?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeIndexEntry.allocationSize(value) + return 1UL + FfiConverterTypeIntegrityPolicy.allocationSize(value) } } - override fun write(value: IndexEntry?, buf: ByteBuffer) { + override fun write(value: IntegrityPolicy?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeIndexEntry.write(value, buf) + FfiConverterTypeIntegrityPolicy.write(value, buf) } } } @@ -11053,28 +12845,28 @@ public object FfiConverterOptionalTypeIndexEntry: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): IndexReadOptions? { +public object FfiConverterOptionalTypePathResolver: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): PathResolver? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeIndexReadOptions.read(buf) + return FfiConverterTypePathResolver.read(buf) } - override fun allocationSize(value: IndexReadOptions?): ULong { + override fun allocationSize(value: PathResolver?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeIndexReadOptions.allocationSize(value) + return 1UL + FfiConverterTypePathResolver.allocationSize(value) } } - override fun write(value: IndexReadOptions?, buf: ByteBuffer) { + override fun write(value: PathResolver?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeIndexReadOptions.write(value, buf) + FfiConverterTypePathResolver.write(value, buf) } } } @@ -11085,28 +12877,28 @@ public object FfiConverterOptionalTypeIndexReadOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): RemoteFetchOptions? { +public object FfiConverterOptionalTypeSourceIntegrityCheckMode: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): SourceIntegrityCheckMode? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeRemoteFetchOptions.read(buf) + return FfiConverterTypeSourceIntegrityCheckMode.read(buf) } - override fun allocationSize(value: RemoteFetchOptions?): ULong { + override fun allocationSize(value: SourceIntegrityCheckMode?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeRemoteFetchOptions.allocationSize(value) + return 1UL + FfiConverterTypeSourceIntegrityCheckMode.allocationSize(value) } } - override fun write(value: RemoteFetchOptions?, buf: ByteBuffer) { + override fun write(value: SourceIntegrityCheckMode?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeRemoteFetchOptions.write(value, buf) + FfiConverterTypeSourceIntegrityCheckMode.write(value, buf) } } } @@ -11117,28 +12909,28 @@ public object FfiConverterOptionalTypeRemoteFetchOptions: FfiConverterRustBuffer /** * @suppress */ -public object FfiConverterOptionalTypeRemoteOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): RemoteOptions? { +public object FfiConverterOptionalTypeVersion: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): Version? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeRemoteOptions.read(buf) + return FfiConverterTypeVersion.read(buf) } - override fun allocationSize(value: RemoteOptions?): ULong { + override fun allocationSize(value: Version?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeRemoteOptions.allocationSize(value) + return 1UL + FfiConverterTypeVersion.allocationSize(value) } } - override fun write(value: RemoteOptions?, buf: ByteBuffer) { + override fun write(value: Version?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeRemoteOptions.write(value, buf) + FfiConverterTypeVersion.write(value, buf) } } } @@ -11149,28 +12941,28 @@ public object FfiConverterOptionalTypeRemoteOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): UpdaterIntegrityOptions? { +public object FfiConverterOptionalSequenceTypeSignatureVerifyKey: FfiConverterRustBuffer?> { + override fun read(buf: ByteBuffer): List? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeUpdaterIntegrityOptions.read(buf) + return FfiConverterSequenceTypeSignatureVerifyKey.read(buf) } - override fun allocationSize(value: UpdaterIntegrityOptions?): ULong { + override fun allocationSize(value: List?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeUpdaterIntegrityOptions.allocationSize(value) + return 1UL + FfiConverterSequenceTypeSignatureVerifyKey.allocationSize(value) } } - override fun write(value: UpdaterIntegrityOptions?, buf: ByteBuffer) { + override fun write(value: List?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeUpdaterIntegrityOptions.write(value, buf) + FfiConverterSequenceTypeSignatureVerifyKey.write(value, buf) } } } @@ -11181,28 +12973,28 @@ public object FfiConverterOptionalTypeUpdaterIntegrityOptions: FfiConverterRustB /** * @suppress */ -public object FfiConverterOptionalTypeUpdaterOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): UpdaterOptions? { +public object FfiConverterOptionalMapStringString: FfiConverterRustBuffer?> { + override fun read(buf: ByteBuffer): Map? { if (buf.get().toInt() == 0) { return null } - return FfiConverterTypeUpdaterOptions.read(buf) + return FfiConverterMapStringString.read(buf) } - override fun allocationSize(value: UpdaterOptions?): ULong { + override fun allocationSize(value: Map?): ULong { if (value == null) { return 1UL } else { - return 1UL + FfiConverterTypeUpdaterOptions.allocationSize(value) + return 1UL + FfiConverterMapStringString.allocationSize(value) } } - override fun write(value: UpdaterOptions?, buf: ByteBuffer) { + override fun write(value: Map?, buf: ByteBuffer) { if (value == null) { buf.put(0) } else { buf.put(1) - FfiConverterTypeUpdaterOptions.write(value, buf) + FfiConverterMapStringString.write(value, buf) } } } @@ -11213,28 +13005,24 @@ public object FfiConverterOptionalTypeUpdaterOptions: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): UpdaterSignatureOptions? { - if (buf.get().toInt() == 0) { - return null +public object FfiConverterSequenceString: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterString.read(buf) } - return FfiConverterTypeUpdaterSignatureOptions.read(buf) } - override fun allocationSize(value: UpdaterSignatureOptions?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypeUpdaterSignatureOptions.allocationSize(value) - } + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.map { FfiConverterString.allocationSize(it) }.sum() + return sizeForLength + sizeForItems } - override fun write(value: UpdaterSignatureOptions?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypeUpdaterSignatureOptions.write(value, buf) + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterString.write(it, buf) } } } @@ -11245,28 +13033,52 @@ public object FfiConverterOptionalTypeUpdaterSignatureOptions: FfiConverterRustB /** * @suppress */ -public object FfiConverterOptionalTypeBundleResolver: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleResolver? { - if (buf.get().toInt() == 0) { - return null +public object FfiConverterSequenceTypeBundleUpdate: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeBundleUpdate.read(buf) } - return FfiConverterTypeBundleResolver.read(buf) } - override fun allocationSize(value: BundleResolver?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypeBundleResolver.allocationSize(value) + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.map { FfiConverterTypeBundleUpdate.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeBundleUpdate.write(it, buf) + } + } +} + + + + +/** + * @suppress + */ +public object FfiConverterSequenceTypeManifestPruneResult: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeManifestPruneResult.read(buf) } } - override fun write(value: BundleResolver?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypeBundleResolver.write(value, buf) + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.map { FfiConverterTypeManifestPruneResult.allocationSize(it) }.sum() + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeManifestPruneResult.write(it, buf) } } } @@ -11277,28 +13089,24 @@ public object FfiConverterOptionalTypeBundleResolver: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): BundleSourceVerifyMode? { - if (buf.get().toInt() == 0) { - return null +public object FfiConverterSequenceTypeManifestRemoveResult: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeManifestRemoveResult.read(buf) } - return FfiConverterTypeBundleSourceVerifyMode.read(buf) } - override fun allocationSize(value: BundleSourceVerifyMode?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypeBundleSourceVerifyMode.allocationSize(value) - } + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.map { FfiConverterTypeManifestRemoveResult.allocationSize(it) }.sum() + return sizeForLength + sizeForItems } - override fun write(value: BundleSourceVerifyMode?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypeBundleSourceVerifyMode.write(value, buf) + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeManifestRemoveResult.write(it, buf) } } } @@ -11309,28 +13117,24 @@ public object FfiConverterOptionalTypeBundleSourceVerifyMode: FfiConverterRustBu /** * @suppress */ -public object FfiConverterOptionalTypeHostnameSegment: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): HostnameSegment? { - if (buf.get().toInt() == 0) { - return null +public object FfiConverterSequenceTypeManifestSetCurrentVersionResult: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeManifestSetCurrentVersionResult.read(buf) } - return FfiConverterTypeHostnameSegment.read(buf) } - override fun allocationSize(value: HostnameSegment?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypeHostnameSegment.allocationSize(value) - } + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.map { FfiConverterTypeManifestSetCurrentVersionResult.allocationSize(it) }.sum() + return sizeForLength + sizeForItems } - override fun write(value: HostnameSegment?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypeHostnameSegment.write(value, buf) + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeManifestSetCurrentVersionResult.write(it, buf) } } } @@ -11341,28 +13145,24 @@ public object FfiConverterOptionalTypeHostnameSegment: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): IntegrityPolicy? { - if (buf.get().toInt() == 0) { - return null +public object FfiConverterSequenceTypeManifestStageResult: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeManifestStageResult.read(buf) } - return FfiConverterTypeIntegrityPolicy.read(buf) } - override fun allocationSize(value: IntegrityPolicy?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypeIntegrityPolicy.allocationSize(value) - } + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.map { FfiConverterTypeManifestStageResult.allocationSize(it) }.sum() + return sizeForLength + sizeForItems } - override fun write(value: IntegrityPolicy?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypeIntegrityPolicy.write(value, buf) + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeManifestStageResult.write(it, buf) } } } @@ -11373,28 +13173,24 @@ public object FfiConverterOptionalTypeIntegrityPolicy: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): PathResolver? { - if (buf.get().toInt() == 0) { - return null +public object FfiConverterSequenceTypeSignatureVerifyKey: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeSignatureVerifyKey.read(buf) } - return FfiConverterTypePathResolver.read(buf) } - override fun allocationSize(value: PathResolver?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypePathResolver.allocationSize(value) - } + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.map { FfiConverterTypeSignatureVerifyKey.allocationSize(it) }.sum() + return sizeForLength + sizeForItems } - override fun write(value: PathResolver?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypePathResolver.write(value, buf) + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeSignatureVerifyKey.write(it, buf) } } } @@ -11405,28 +13201,24 @@ public object FfiConverterOptionalTypePathResolver: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): SignatureVerification? { - if (buf.get().toInt() == 0) { - return null +public object FfiConverterSequenceTypeSourceListItem: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeSourceListItem.read(buf) } - return FfiConverterTypeSignatureVerification.read(buf) } - override fun allocationSize(value: SignatureVerification?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypeSignatureVerification.allocationSize(value) - } + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.map { FfiConverterTypeSourceListItem.allocationSize(it) }.sum() + return sizeForLength + sizeForItems } - override fun write(value: SignatureVerification?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypeSignatureVerification.write(value, buf) + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeSourceListItem.write(it, buf) } } } @@ -11437,28 +13229,24 @@ public object FfiConverterOptionalTypeSignatureVerification: FfiConverterRustBuf /** * @suppress */ -public object FfiConverterOptionalTypeVersion: FfiConverterRustBuffer { - override fun read(buf: ByteBuffer): Version? { - if (buf.get().toInt() == 0) { - return null +public object FfiConverterSequenceTypeUpdaterDownloadResult: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeUpdaterDownloadResult.read(buf) } - return FfiConverterTypeVersion.read(buf) } - override fun allocationSize(value: Version?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterTypeVersion.allocationSize(value) - } + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.map { FfiConverterTypeUpdaterDownloadResult.allocationSize(it) }.sum() + return sizeForLength + sizeForItems } - override fun write(value: Version?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterTypeVersion.write(value, buf) + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeUpdaterDownloadResult.write(it, buf) } } } @@ -11469,28 +13257,24 @@ public object FfiConverterOptionalTypeVersion: FfiConverterRustBuffer /** * @suppress */ -public object FfiConverterOptionalMapStringString: FfiConverterRustBuffer?> { - override fun read(buf: ByteBuffer): Map? { - if (buf.get().toInt() == 0) { - return null +public object FfiConverterSequenceTypeUpdaterInstallResult: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeUpdaterInstallResult.read(buf) } - return FfiConverterMapStringString.read(buf) } - override fun allocationSize(value: Map?): ULong { - if (value == null) { - return 1UL - } else { - return 1UL + FfiConverterMapStringString.allocationSize(value) - } + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.map { FfiConverterTypeUpdaterInstallResult.allocationSize(it) }.sum() + return sizeForLength + sizeForItems } - override fun write(value: Map?, buf: ByteBuffer) { - if (value == null) { - buf.put(0) - } else { - buf.put(1) - FfiConverterMapStringString.write(value, buf) + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeUpdaterInstallResult.write(it, buf) } } } @@ -11501,24 +13285,24 @@ public object FfiConverterOptionalMapStringString: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { +public object FfiConverterSequenceTypeUpdaterInstallTarget: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { val len = buf.getInt() - return List(len) { - FfiConverterString.read(buf) + return List(len) { + FfiConverterTypeUpdaterInstallTarget.read(buf) } } - override fun allocationSize(value: List): ULong { + override fun allocationSize(value: List): ULong { val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterString.allocationSize(it) }.sum() + val sizeForItems = value.map { FfiConverterTypeUpdaterInstallTarget.allocationSize(it) }.sum() return sizeForLength + sizeForItems } - override fun write(value: List, buf: ByteBuffer) { + override fun write(value: List, buf: ByteBuffer) { buf.putInt(value.size) value.iterator().forEach { - FfiConverterString.write(it, buf) + FfiConverterTypeUpdaterInstallTarget.write(it, buf) } } } @@ -11529,24 +13313,24 @@ public object FfiConverterSequenceString: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { +public object FfiConverterSequenceTypeUpdaterRollbackResult: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { val len = buf.getInt() - return List(len) { - FfiConverterTypeListBundleItem.read(buf) + return List(len) { + FfiConverterTypeUpdaterRollbackResult.read(buf) } } - override fun allocationSize(value: List): ULong { + override fun allocationSize(value: List): ULong { val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterTypeListBundleItem.allocationSize(it) }.sum() + val sizeForItems = value.map { FfiConverterTypeUpdaterRollbackResult.allocationSize(it) }.sum() return sizeForLength + sizeForItems } - override fun write(value: List, buf: ByteBuffer) { + override fun write(value: List, buf: ByteBuffer) { buf.putInt(value.size) value.iterator().forEach { - FfiConverterTypeListBundleItem.write(it, buf) + FfiConverterTypeUpdaterRollbackResult.write(it, buf) } } } @@ -11557,24 +13341,24 @@ public object FfiConverterSequenceTypeListBundleItem: FfiConverterRustBuffer> { - override fun read(buf: ByteBuffer): List { +public object FfiConverterSequenceTypeUpdaterRollbackTarget: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { val len = buf.getInt() - return List(len) { - FfiConverterTypeListRemoteBundleInfo.read(buf) + return List(len) { + FfiConverterTypeUpdaterRollbackTarget.read(buf) } } - override fun allocationSize(value: List): ULong { + override fun allocationSize(value: List): ULong { val sizeForLength = 4UL - val sizeForItems = value.map { FfiConverterTypeListRemoteBundleInfo.allocationSize(it) }.sum() + val sizeForItems = value.map { FfiConverterTypeUpdaterRollbackTarget.allocationSize(it) }.sum() return sizeForLength + sizeForItems } - override fun write(value: List, buf: ByteBuffer) { + override fun write(value: List, buf: ByteBuffer) { buf.putInt(value.size) value.iterator().forEach { - FfiConverterTypeListRemoteBundleInfo.write(it, buf) + FfiConverterTypeUpdaterRollbackTarget.write(it, buf) } } } @@ -11660,6 +13444,84 @@ public object FfiConverterMapStringTypeIndexEntry: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): Map { + val len = buf.getInt() + return buildMap(len) { + repeat(len) { + val k = FfiConverterString.read(buf) + val v = FfiConverterTypeManifestRemoveData.read(buf) + this[k] = v + } + } + } + + override fun allocationSize(value: Map): ULong { + val spaceForMapSize = 4UL + val spaceForChildren = value.map { (k, v) -> + FfiConverterString.allocationSize(k) + + FfiConverterTypeManifestRemoveData.allocationSize(v) + }.sum() + return spaceForMapSize + spaceForChildren + } + + override fun write(value: Map, buf: ByteBuffer) { + buf.putInt(value.size) + // The parens on `(k, v)` here ensure we're calling the right method, + // which is important for compatibility with older android devices. + // Ref https://blog.danlew.net/2017/03/16/kotlin-puzzler-whose-line-is-it-anyways/ + value.forEach { (k, v) -> + FfiConverterString.write(k, buf) + FfiConverterTypeManifestRemoveData.write(v, buf) + } + } +} + + + + +/** + * @suppress + */ +public object FfiConverterMapStringTypeManifestStageData: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): Map { + val len = buf.getInt() + return buildMap(len) { + repeat(len) { + val k = FfiConverterString.read(buf) + val v = FfiConverterTypeManifestStageData.read(buf) + this[k] = v + } + } + } + + override fun allocationSize(value: Map): ULong { + val spaceForMapSize = 4UL + val spaceForChildren = value.map { (k, v) -> + FfiConverterString.allocationSize(k) + + FfiConverterTypeManifestStageData.allocationSize(v) + }.sum() + return spaceForMapSize + spaceForChildren + } + + override fun write(value: Map, buf: ByteBuffer) { + buf.putInt(value.size) + // The parens on `(k, v)` here ensure we're calling the right method, + // which is important for compatibility with older android devices. + // Ref https://blog.danlew.net/2017/03/16/kotlin-puzzler-whose-line-is-it-anyways/ + value.forEach { (k, v) -> + FfiConverterString.write(k, buf) + FfiConverterTypeManifestStageData.write(v, buf) + } + } +} + + + + @@ -11728,5 +13590,45 @@ public object FfiConverterMapStringTypeIndexEntry: FfiConverterRustBuffer + UniffiLib.uniffi_wvb_ffi_fn_func_extension( + + _status) +} + ) + } + + fun `mimeType`(): kotlin.String { + return FfiConverterString.lift( + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_func_mime_type( + + _status) +} + ) + } + + fun `runtimeVersion`(): kotlin.UByte { + return FfiConverterUByte.lift( + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_func_runtime_version( + + _status) +} + ) + } + + fun `updateProtocolVersion`(): kotlin.String { + return FfiConverterString.lift( + uniffiRustCall() { _status -> + UniffiLib.uniffi_wvb_ffi_fn_func_update_protocol_version( + + _status) +} + ) + } + diff --git a/lib/src/main/kotlin/dev/wvb/WvbRustlsPlatformVerififer.kt b/lib/src/main/kotlin/dev/wvb/WvbRustlsPlatformVerififer.kt new file mode 100644 index 0000000..8e0abaf --- /dev/null +++ b/lib/src/main/kotlin/dev/wvb/WvbRustlsPlatformVerififer.kt @@ -0,0 +1,22 @@ +package dev.wvb + +import android.content.Context +import androidx.annotation.Keep + +/** Android runtime required by the native HTTPS certificate verifier. */ +@Keep +object WvbAndroid { + init { + System.loadLibrary("wvb_ffi") + } + + /** + * Call before using Remote or ProxyProtocolHandler directly. Repeated calls are safe. + * Only the application context is retained for the lifetime of the process. + */ + fun initialize(context: Context) { + initializeAndroid(context.applicationContext) + } + + private external fun initializeAndroid(context: Context) +} diff --git a/scripts/install.mjs b/scripts/install.mjs index 314ce42..4caec7c 100755 --- a/scripts/install.mjs +++ b/scripts/install.mjs @@ -5,16 +5,16 @@ // webview-bundle/webview-bundle repository into this Gradle project. // // It fetches the GitHub release asset `android.zip` for a given tag and installs -// the Android variant (`lib-android`) into the `lib` module: +// the Android variant (`lib`) into the `lib` module: // - the Kotlin bindings -> lib/src/main/kotlin/... (overwrite only — // existing files that are not part of the asset are kept) // - the JNI libraries -> lib/src/main/jniLibs/... (replaced wholesale, // so stale ABIs from a previous install are removed) // // `android.zip` is laid out as (see .output/android/ for a reference): -// lib-android/src/main/jniLibs//libwvb_ffi.so -// lib-android/src/main/kotlin/dev/wvb/wvb_ffi.kt -// lib-jvm/src/main/kotlin/dev/wvb/wvb_ffi.kt +// lib/src/main/jniLibs//libwvb_ffi.so +// lib/src/main/kotlin/dev/wvb/WvbFFI.kt +// lib/src/main/kotlin/dev/wvb/WvbRustlsPlatformVerififer.kt // // Tags follow the upstream convention: // - release: ffi/ e.g. ffi/0.1.0 @@ -53,9 +53,7 @@ import { fileURLToPath } from "node:url"; const REPO_DEFAULT = "webview-bundle/webview-bundle"; const ANDROID_ASSET = "android.zip"; -// The Android library variant inside android.zip (ships Kotlin + jniLibs). The -// sibling `lib-jvm` variant is Kotlin-only and not used by this module. -const ANDROID_MODULE = "lib-android"; +const ANDROID_MODULE = "lib"; const USER_AGENT = "webview-bundle-android-install-ffi"; const ROOT_DIR = resolve(dirname(fileURLToPath(import.meta.url)), ".."); @@ -256,7 +254,7 @@ function walkFiles(dir) { } // Locate the `src/` directory of the Android variant inside the extracted -// android.zip (e.g. lib-android/src). BFS for the shallowest `lib-android` +// android.zip (e.g. lib/src). BFS for the shallowest `lib` // directory so an extra wrapping folder in the archive wouldn't break this. function findAndroidSrcDir(root) { const queue = [root]; @@ -300,12 +298,23 @@ function installAndroidBindings(androidZipPath, tmpDir) { if (files.length === 0) die(`no files found under '${ANDROID_MODULE}/src' in ${ANDROID_ASSET}`); + for (const required of [ + "main/kotlin/dev/wvb/WvbRustlsPlatformVerififer.kt", + "main/kotlin/dev/wvb/WvbFFI.kt", + ]) { + if (!existsSync(join(srcDir, required))) + die(`FFI asset is missing ${required}; build/install an updated android.zip`); + } + // jniLibs is fully managed by this script (see .gitignore); wipe it so a // dropped or renamed ABI from a previous install does not linger. rmSync(JNILIBS_DIR, { recursive: true, force: true }); + // Remove former filenames to avoid duplicate Kotlin declarations. + rmSync(join(LIB_SRC_DIR, "main/kotlin/dev/wvb/wvb_ffi.kt"), { force: true }); + rmSync(join(LIB_SRC_DIR, "main/kotlin/dev/wvb/WvbAndroid.kt"), { force: true }); - // Mirror lib-android/src/ into lib/src/, so e.g. - // main/kotlin/dev/wvb/wvb_ffi.kt and main/jniLibs//libwvb_ffi.so + // Mirror lib/src/ into lib/src/, so e.g. + // main/kotlin/dev/wvb/WvbFFI.kt and main/jniLibs//libwvb_ffi.so // land in the right places. Kotlin files overwrite in place; any other // hand-written source under lib/src is left untouched. const installed = []; diff --git a/settings.gradle.kts b/settings.gradle.kts index 4ba3fed..7564979 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,6 +10,10 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { + url = uri("https://raw.githubusercontent.com/rustls/rustls-platform-verifier/maven-archive/android-release-support/maven/") + content { includeGroup("org.rustls") } + } } } diff --git a/testapp/src/main/assets/bundles/manifest.json b/testapp/src/main/assets/bundles/manifest.json index 4a0ffca..9c95e12 100644 --- a/testapp/src/main/assets/bundles/manifest.json +++ b/testapp/src/main/assets/bundles/manifest.json @@ -1,13 +1,13 @@ { "manifestVersion": 1, - "entries": { + "bundles": { "testbed": { + "currentVersion": "0.4.0", "versions": { - "0.2.0": { - "integrity": "sha256:jdi4x7cstlNgnReMU7NS1OE5EYmiLF87GYBSYh9tqxE=" + "0.4.0": { + "integrity": "sha256:J63kXbcRISIgXrj9gR/2E8O3XsLdybzE+bwa2nMgio8=" } - }, - "currentVersion": "0.2.0" + } } } } diff --git a/testapp/src/main/assets/bundles/testbed/0.4.0.wvb b/testapp/src/main/assets/bundles/testbed/0.4.0.wvb new file mode 100644 index 0000000..236fddb Binary files /dev/null and b/testapp/src/main/assets/bundles/testbed/0.4.0.wvb differ diff --git a/testapp/src/main/assets/bundles/testbed/testbed_0.2.0.wvb b/testapp/src/main/assets/bundles/testbed/testbed_0.2.0.wvb deleted file mode 100644 index 8e25fc8..0000000 Binary files a/testapp/src/main/assets/bundles/testbed/testbed_0.2.0.wvb and /dev/null differ diff --git a/testapp/src/main/kotlin/dev/wvb/testapp/MainActivity.kt b/testapp/src/main/kotlin/dev/wvb/testapp/MainActivity.kt index 4e56642..f09fad0 100644 --- a/testapp/src/main/kotlin/dev/wvb/testapp/MainActivity.kt +++ b/testapp/src/main/kotlin/dev/wvb/testapp/MainActivity.kt @@ -33,7 +33,9 @@ class MainActivity : Activity() { WebViewBundleConfig( protocols = listOf(WebViewBundleProtocol.bundle()), updater = WebViewBundleUpdaterConfig( - remote = WebViewBundleRemoteConfig(endpoint = REMOTE_ENDPOINT), + remote = WebViewBundleRemoteConfig( + baseUrl = intent.getStringExtra("wvbRemoteUrl") ?: REMOTE_ENDPOINT, + ), ), onError = { error -> Log.e(TAG, "handler error", error) }, ), @@ -101,7 +103,7 @@ class MainActivity : Activity() { const val TAG = "WvbTestApp" const val START_URL = "https://testbed.wvb/" - /** The playground remote the e2e testbed spec downloads the `testbed` bundle from. */ + /** Default remote for manual use; E2E supplies wvbRemoteUrl at launch. */ const val REMOTE_ENDPOINT = "https://playground-remote.wvb.dev" } }