import type { CanvasKit, EmbindEnumEntity } from "canvaskit-wasm"; import type { SkJSIInstance } from "../types"; export const throwNotImplementedOnRNWeb = (): T => { if (typeof jest !== "undefined") { return jest.fn() as unknown as T; } throw new Error("Not implemented on React Native Web"); }; export abstract class Host { readonly CanvasKit: CanvasKit; constructor(CanvasKit: CanvasKit) { this.CanvasKit = CanvasKit; } } export abstract class BaseHostObject extends Host implements SkJSIInstance { readonly __typename__: N; ref: T; constructor(CanvasKit: CanvasKit, ref: T, typename: N) { super(CanvasKit); this.ref = ref; this.__typename__ = typename; } dispose() { this[Symbol.dispose](); } [Symbol.dispose](): void { if ( this.ref !== null && typeof this.ref === "object" && "delete" in this.ref && typeof this.ref.delete === "function" ) { // Renderer-owned and user-owned disposal can overlap (and emscripten // throws on double delete) — make disposing an already-deleted object // a no-op. const ref = this.ref as unknown as { isDeleted?: () => boolean }; if (typeof ref.isDeleted === "function" && ref.isDeleted()) { return; } this.ref.delete(); } } } export abstract class HostObject extends BaseHostObject< T, N > { static fromValue(value: SkJSIInstance) { return (value as HostObject).ref; } } export const getEnum = ( CanvasKit: CanvasKit, name: keyof CanvasKit, v: number ): EmbindEnumEntity => { const e = CanvasKit[name]; if (typeof e !== "function") { throw new Error(`${name} is not an number`); } const result = Object.values(e).find( (entry) => entry !== null && typeof entry === "object" && "value" in entry && entry.value === v ); if (!result) { throw new Error( `Enum ${name} does not have value ${v} on React Native Web` ); } return result; }; export const optEnum = ( CanvasKit: CanvasKit, name: keyof CanvasKit, v: number | undefined ): EmbindEnumEntity | undefined => { return v === undefined ? undefined : getEnum(CanvasKit, name, v); };