|
Creador de PowerRustCOBOL
|
21.10.2026 06:56
|
|
Posts: 395
|
|
Enviados: 31
|
|
Recibidos: 171
|
|
WASM-017 — Arquitectura del módulo, modelo de memoria, hilos y frontera JavaScript
Estado: borrador, con las decisiones del operador de 2026-10-20 incorporadas. Depende de WASM-002, 010 y 016. Ajusta WASM-002, 010, 011, 013, 015 y 016.
Requisitos
Carga y vida del formulario
R1 — Build emite un módulo de programa para todo el proyecto, con el Common Code de cada formulario copiado, autocontenido (WASM-010 R2). El cargador lo obtiene mediante compilación en streaming e inicia el formulario principal en cuanto está listo.
R2 — Cada instancia de formulario tiene su WORKING-STORAGE en una región de la memoria de datos, asignada al crearla y liberada al destruirla (especificación 049: no residente y no conservada). Tamaño fijo durante la compilación (R7): datos estáticos más, para cada formulario, Instances × su tamaño. Instances es una propiedad del formulario (valor predeterminado: 4 para formularios que OpenFormSync/OpenFormAsync puedan abrir; 1 en los demás). Crear una instancia por encima de Instances provoca el error de ejecución de WASM-010 R11 con el nombre del formulario.
R3 — Cargador mediante fetch + instanciación en streaming. La integración ES-module es opcional y solo se utiliza mediante detección de funcionalidades (R6, R18). Las partes pesadas del player (WASM-016 R13) se obtienen en el primer uso mediante el mismo cargador.
R4 — El tiempo de vida sigue a COBOL, no a la pila: WORKING-STORAGE de un programa vive desde el primer CALL hasta CANCEL o hasta que se destruye la instancia del formulario. Excepción: programa INITIAL, que comienza limpio en cada llamada y cuyo estado se descarta al retornar.
R5 — Al destruir una instancia, el módulo libera y reinicializa su región, y el cargador libera todas las referencias (listeners, temporizadores, llamadas pendientes, entradas de la tabla del host). Al desmontar la aplicación, el cargador libera el módulo y las memorias y termina los Workers. La compilación de debug demuestra ambos casos (R20).
R6 — No se utiliza Component Model en la v1 (compatibilidad de Chrome no establecida). La API del host sigue utilizando imports y exports simples. Se reconsiderará cuando los tres motores tengan compatibilidad nativa (Q7).
Modelo de memoria
R7 — Memoria de datos de tamaño fijo durante la compilación (R2). Código generado sin memory.grow. Un dato que no se pueda dimensionar provoca un error de compilación que identifica el elemento.
R8 — Frames de texto y JSON en la arena de transporte de tamaño fijo, obtenido del límite de payload del proyecto (WASM-005 R11). Multi-memory: la arena es la memoria 1, separada de los datos (memoria 0). Single-memory: región reservada de la memoria 0. La API del host es la misma: offset, length y selector de memoria.
R9 — Multi-memory es el valor predeterminado del módulo (operador, 2026-10-20). Build también produce la variante single-memory (sin ninguna instrucción multi-memory), utilizada siempre para iOS (multi-memory desactivado de forma predeterminada) y siempre que la matriz de navegadores incluya Safari o la vista web de iOS (predeterminado). El paquete Web incluye ambas y el cargador comprueba WebAssembly.validate y carga la adecuada. Un proyecto sin Safari puede elegir “multi-memory only”; Build lo rechaza si la matriz incluye Safari (AC7). Solo el módulo emitido utiliza una segunda memoria; el player (Rust) no.
R10 — El host nunca conserva TypedArray o DataView sobre la memoria del módulo entre llamadas: obtiene la vista en cada uso. El player no entrega a JavaScript vistas que sobrevivan a una llamada; también se aplica a la memoria compartida.
La frontera
R11 — API del host de granularidad gruesa: las escrituras de propiedades de un handler se acumulan y se entregan en una llamada al finalizar o al suspenderse, y las lecturas reflejan las escrituras anteriores; un evento es una llamada; una llamada remota es una solicitud y una respuesta; ninguna llamada al host por iteración de bucle. Un programa de dibujo sigue la misma regla: los comandos se envían a un buffer en la arena y se ejecutan en una llamada (WASM-018 R6).
R12 — El texto cruza la frontera una vez en cada dirección: UTF-8 en la arena frente a cadenas JavaScript mediante TextEncoder/TextDecoder. Cuando el navegador ofrece JS String Builtins, el cargador puede utilizarlos (mediante detección de funcionalidades).
R13 — Los datos que no necesitan el programa (bytes de un archivo arrastrado, imagen, buffers de píxeles de los objetos gráficos) no pasan por el módulo: el player los mueve (WASM-014 R15, WASM-018).
R14 — Todo objeto Rust expuesto a JavaScript mediante wasm-bindgen tiene una liberación explícita (free() o dispose), llamada por unmount() y por el cargador durante el desmontaje. Pocos objetos y enumerados; ninguno queda solo a cargo del GC de JavaScript. Se aplica a los handles de los objetos gráficos (WASM-018).
R15 — Un panic termina esa instancia de forma limpia: la página anfitriona muestra un error legible con una acción de recarga y dispara un evento de error. Un error de ejecución COBOL no es un panic (WASM-010 R11). En la variante threaded, un panic en un worker también termina la instancia.
Compilación y base mínima
R16 — Player con perfil de release que prioriza el tamaño: lto, codegen-units = 1, panic = "abort", símbolos eliminados, opt-level según mediciones ("z" frente a "s") y un paso de wasm-opt; tamaños notificados (WASM-016 R13). Dos variantes del mismo código fuente: plain (Rust estable, base mínima) y threaded (nightly fijado, std reconstruida, atomics, bulk memory, memoria compartida, --target web, wasm-bindgen-rayon). El resto del workspace permanece en Rust estable, MSRV 1.92; nightly queda limitado al paso del player.
R17 — La compilación del producto ejecuta wasm-bindgen CLI con versión fijada, Binaryen wasm-opt con versión fijada y el empaquetador (WASM-002 Q2), nunca wasm-pack. Estas herramientas y nightly existen solo en la compilación del producto; se aplican las reglas de cadena de suministro (WASM-013 R9); la fecha de nightly se registra en cada compilación.
R18 — Base mínima de funcionalidades WebAssembly y matriz de navegadores (Chrome y Edge, Firefox, Safari, vista web de iOS, Android WebView), a partir de MDN y Can I Use en /plan. El cargador comprueba y selecciona de forma independiente: variante del módulo (R9), variante del player (R19) y aceleración opcional (JS String Builtins, ES-module). Si no se cumple la base mínima, muestra el mensaje de WASM-002 R15.
Concurrencia
R19 — Los hilos y Rayon están incluidos en la v1 (operador, 2026-10-20):
(a) Rayon se ejecuta en el player y en los objetos gráficos (filtros y remuestreo de imágenes, rasterización de gráficos y canvas, física, ordenación y filtrado de DataGrid), en un pool dimensionado según navigator.hardwareConcurrency (limitado, configurable), en el player threaded;
(b) el módulo se ejecuta en un Worker dedicado cuando la página tiene aislamiento entre orígenes; las llamadas al host se redirigen al hilo principal (escrituras por lotes, lecturas mediante espera en memoria compartida) para que un bucle largo no congele la página. Sin aislamiento, el módulo se ejecuta en el hilo principal con cesión cooperativa (WASM-010 R9). Los resultados no dependen del modo;
© el aislamiento (COOP: same-origin con COEP: require-corp o credentialless) se exige para los hilos y es una propiedad del despliegue: Build imprime las cabeceras y ofrece un shim de service worker opcional (desactivado de forma predeterminada); los recursos de otros orígenes deben permitirlo (CORS o CORP);
(d) una página que integra la aplicación solo está aislada si la página anfitriona lo está; en caso contrario, utiliza el player plain y el hilo principal;
(e) nada exige hilos para garantizar la corrección: todas las funcionalidades funcionan en el player plain y en el hilo principal, y una prueba ejecuta los mismos casos en cada uno (R20);
(f) resultados deterministas: una reducción Rayon no puede depender del número de hilos (WASM-018 R20).
R20 — Suite de pruebas para cada combinación de variante del módulo, variante del player y modo (Worker, hilo principal): carga (módulo obtenido al inicio; parte pesada solo en el primer uso); liberación (abrir y cerrar un formulario muchas veces vuelve a la línea de base; unmount termina los Workers); memoria fija; procesamiento por lotes (un handler con 1000 propiedades realiza como máximo un número declarado de llamadas); cadenas (ida y vuelta UTF-8 con multibyte); vista (una llamada que hace crecer la memoria del player mantiene las lecturas correctas); base mínima y matriz (un navegador por debajo de la base mínima recibe el mensaje); aislamiento (con y sin COOP/COEP, se elige la variante correcta y los resultados son los mismos); cesión (un bucle largo mantiene los frames dentro de un plazo en el hilo principal).
Objetivos: módulo que utiliza streaming, se compila mientras se descarga e inicia rápidamente, con partes pesadas bajo demanda; memoria del formulario devuelta al destruirlo, demostrado mediante una prueba; modelo de memoria sin crecimiento y sin vistas desconectadas; multi-memory de forma predeterminada y single-memory donde falte; API del host con bajo coste al cruzarla; concurrencia real donde la plataforma lo permite, nunca exigida para la corrección; compilación compacta y reproducible, con base mínima y matriz impuestas por Build.
Fuera del alcance: hilos en la semántica de COBOL; Component Model, WebAssembly GC y memorias de 64 bits en la v1; cifras de rendimiento (la especificación solo las hace medibles).
Tabla de decisiones de tratamiento (§1): 1a carga bajo demanda (un módulo; partes pesadas del player: gráficos, mapas, Viewer, motor 3D); 1b Component Model no adoptado; 1c ES-module opcional y detectado; 1d “destruir al retornar” adaptado a COBOL (región por formulario, INITIAL descartado); 2a JS String Builtins opcionales; 2b multi-memory predeterminado con la arena como memoria 1; 3 .free() para el player y los objetos gráficos; 4 sin memory.grow en el módulo; 5a llamadas de granularidad gruesa como regla; 5b hilos y Rayon adoptados; 6 perfil que prioriza el tamaño y wasm-opt para el player, nightly fijado para la variante threaded.
Cuestiones:
Q1 — Un módulo por proyecto — decidido (2026-10-20). Coste: primera descarga mayor, mitigada mediante streaming, compresión y partes bajo demanda.
Q2 — Presupuesto de cesión (ms) y número predeterminado de Workers — abierto: sugerencia hardwareConcurrency menos uno, limitado a 8.
Q3 — Variantes single/multi-memory — decidido (R9).
Q4 — Matriz de navegadores y versiones mínimas (en especial, la versión de iOS más antigua) — abierto, a partir de /plan.
Q5 — Aislamiento en el shell móvil (cabeceras del protocolo de recursos de Tauri; si la vista web de iOS aísla) — abierto. Si no hay aislamiento, se ejecutan el player plain y el hilo principal.
Q6 — wasm-opt — abierto, recomendado: solo en la compilación del player.
Q7 — Reconsiderar Component Model y ES-module — abierto; desencadenante: compatibilidad nativa en Chrome, Firefox y Safari.
Q8 — opt-level — abierto: "z" o "s" según mediciones.
Q9 — Nightly: fecha fijada y si build-std sigue siendo necesario — abierto.
Q10 — Shim de service worker para cabeceras — abierto: ofrecerlo, solo documentarlo o dejarlo fuera.
Estado: borrador. Los hilos, multi-memory y el player threaded se incorporan al player (PROG-45 a PROG-50).
WASM-018 — Canvas 2D, Canvas 3D y objetos gráficos, en todas las plataformas
Estado: borrador (parte 1 del plan implementada; véase la sección 7). Origen: operador, 2026-10-20: controles Canvas2D y Canvas3D y objetos para generar gráficos (juegos, gráficos de datos, manipulación de imágenes), en todas las plataformas, con crates populares y 100 % Rust. Depende de WASM-004, 010, 016 y 017.
Requisitos
El catálogo
R1 — Todas las cajas de herramientas ofrecen dos controles visuales, Canvas2D y Canvas3D, cada uno con propiedades, eventos, métodos, tamaño e icono predeterminados, secciones de Properties, recorrido de ida y vuelta .cfrm, documentación en System KB, prueba en tests/controls/, etiquetas en seis idiomas y nombres de métodos en el vocabulario cerrado.
Canvas2D: Width, Height (píxeles lógicos), PixelRatio, Smoothing, BackgroundColor, TargetFps (0 = redibujado bajo demanda), AutoPresent, AccessibleLabel; eventos onFrame (con milisegundos transcurridos), onPointerDown/Move/Up/Enter/Leave, onWheel, onKeyDown/Up, onTouchStart/Move/End, onResize.
Canvas3D: las mismas propiedades y eventos, más ClearColor, Msaa y Backend de solo lectura (WebGPU, WebGL2, Vulkan, Metal, Dx12, Software).
R2 — Cinco objetos no visuales, colocados en un formulario como Timer o RestClient: ImageBuffer (R11), Plot (R12), Scene3D (R9), Physics2D y Physics3D (R10). Lo que crean (serie, nodo, luz, cuerpo) son handles: enteros que RETURNING devuelve a un elemento de datos y que los métodos reciben. Un handle se libera mediante Release, al eliminar aquello que identifica y al destruir el objeto o formulario (WASM-017 R14).
R3 — Todo en un crate de Rust puro, cobolt-graphics, sin egui, web-sys ni sistema de archivos. Se compila para los destinos del host y para wasm32 en ambas variantes del player. El host desktop y el player solo proporcionan la superficie, los eventos de entrada, el reloj de frames y los bytes de los recursos.
100 % Rust
R4 — Un crate solo se incorpora si: es Rust; ningún script de compilación del conjunto predeterminado de funcionalidades compila C/C++ o enlaza bibliotecas del sistema (cc, cmake, bindgen, pkg-config), excepto las API gráficas del navegador y del SO a las que wgpu accede mediante bindings Rust; licencia permisiva compatible con Apache-2.0; release en los últimos doce meses; compatibilidad con wasm32; MSRV ≤ 1.92 (excepto el nightly del player threaded); supera los controles de dependencias de WASM-013 R9 (sin ring, sin aws-lc-rs). Lista de exclusión de pruebas: font-kit, freetype-sys, harfbuzz-sys, skia-safe, cairo-sys-rs, libwebp-sys, mozjpeg-sys y similares.
R5 — Crates elegidos (salvo que el plan demuestre que alguno incumple R4):
Rasterizador 2D: tiny-skia (CPU, trazados, trazos, líneas discontinuas, gradientes, patrones, máscaras de recorte, modos de mezcla; determinista);
Curvas: kurbo;
Texto: skrifa + rustybuzz + fontdb (contornos, conformación de texto latino, CJK, árabe e índico, búsqueda de fuentes), con unicode-bidi y unicode-linebreak;
Imágenes: image + imageproc + fast_image_resize (códecs de Rust puro, filtros, morfología, remuestreo);
Gráficos de datos: plotters con la funcionalidad de texto ab_glyph y un DrawingBackend propio sobre tiny-skia;
3D: wgpu + naga + glam + bytemuck + gltf (WebGPU y WebGL2 en el navegador; Vulkan, Metal y Dx12 en los demás); la capa de escena es propia;
Física: rapier2d y rapier3d (con parry), con parallel mediante Rayon y enhanced-determinism;
Paralelismo: rayon (en el navegador mediante wasm-bindgen-rayon);
Gamepad: gilrs en desktop; la Gamepad API del navegador mediante el player.
Rechazados, con su motivo: bevy (framework de aplicación, decenas de MB de Wasm, requiere controlar el bucle); three-d (segunda pila gráfica junto a wgpu); macroquad/miniquad (controlan la ventana y el bucle); charming (renderiza con JavaScript); skia-safe y cairo-rs (C o C++); vello (GPU todavía no estable, sustituible después detrás de la misma API).
Lista de visualización y paridad
R6 — Los métodos de dibujo registran comandos en una lista de visualización binaria versionada, definida una vez en cobolt-graphics, que el control ejecuta en una llamada: en Present/Flush, al final de onFrame con AutoPresent y antes de cualquier método que lea la imagen (ToImage, GetPixel, MeasureText, IsPointInPath). En el módulo generado, la lista reside en la arena de transporte y una llamada al host la entrega (WASM-017 R11); en el intérprete, reside en la memoria del host. Todos los hosts decodifican con el mismo Rust.
Canvas2D
R7 — Canvas2D con la semántica de HTML Canvas 2D API donde exista un equivalente (tabla de diferencias en KB):
Estado: Save, Restore, Clear.
Trazados: BeginPath, MoveTo, LineTo, QuadTo, CubicTo, ArcTo, Arc, Ellipse, Rect, RoundRect, ClosePath, Fill, Stroke, Clip.
Formas: FillRect, StrokeRect, ClearRect, DrawLine, DrawCircle, DrawPolygon.
Estilo: SetFillColor, SetStrokeColor, SetLineWidth, SetLineCap, SetLineJoin, SetDash, SetAlpha, SetBlendMode, SetLinearGradient, SetRadialGradient, SetPattern, SetShadow.
Transformaciones: Translate, Rotate, Scale, SetTransform, ResetTransform.
Texto: SetFont, SetTextAlign, DrawText, MeasureText.
Imágenes: DrawImage de un ImageBuffer (completo o rectángulo de origen, con o sin escala); DrawSprite para un frame de una hoja de sprites.
Lectura de vuelta: ToImage, GetPixel, IsPointInPath.
Presentación: Present.
Rasterización en CPU, con antialiasing y determinista (tiny-skia); un canvas grande puede rasterizarse por bloques en paralelo (R20).
R8 — Texto conformado (shaped), bidireccional y con saltos de línea correctos en los seis idiomas, incluidos japonés y chino, con fuentes del conjunto base incorporado o de Assets/. MeasureText devuelve exactamente el espacio que ocupa DrawText.
Canvas3D y Scene3D
R9 — Canvas3D renderiza una Scene3D con wgpu: SetScene, SetCamera, Render, Resize, Screenshot (a un ImageBuffer) y Pick (nodo bajo un píxel, mediante ray casting con parry3d). Scene3D ofrece:
Primitivas: AddBox, AddSphere, AddPlane, AddCylinder, AddCone, AddTorus;
LoadModel de glTF 2.0 o GLB, con mallas, materiales, transformaciones y animaciones esqueléticas y de nodos;
Transformaciones: SetPosition, SetRotation, SetScale, LookAt;
Materiales: color, metallic, roughness, emissive, ImageBuffer como textura, PBR metallic-roughness;
Luces: AddDirectionalLight, AddPointLight, AddSpotLight, SetAmbient, con mapas de sombras para luces direccionales y spot;
SetBackground, SetFog; cámaras AddCamera (perspectiva y ortográfica); SetAnimation/PlayAnimation; Remove; instancing; frustum culling.
Backend identifica lo que se ejecuta (WebGPU, después WebGL2 en la web; Vulkan, Metal o Dx12 nativo; software en las pruebas). Sin backend, muestra un mensaje legible y dispara un evento.
R10 — Physics2D y Physics3D: mundo (CreateWorld con gravedad); cuerpos estáticos, dinámicos y cinemáticos con formas (ball, box, capsule, convex hull, trimesh en 3D); SetPosition, SetVelocity, ApplyForce, ApplyImpulse; articulaciones (fixed, revolute, prismatic); RayCast; Step con paso de tiempo fijo opcional; GetPosition, GetRotation; eventos de colisión; Bind de un cuerpo a un sprite o nodo de Scene3D.
Objetos de imagen y gráficos de datos
R11 — ImageBuffer: Create, LoadAsset, LoadFromBytes, Encode (PNG, JPEG, GIF, WebP, BMP, QOI), Save (desktop escribe un archivo; web lo entrega al navegador o al backend), Resize (nearest, bilinear, Catmull-Rom, Lanczos), Crop, Rotate, Flip, Fill, GetPixel, SetPixel, DrawOnto un Canvas2D, Composite con modos de mezcla, y filtros: grayscale, invert, brightness, contrast, hue, saturation, threshold, blur (Gaussian, box), sharpen, edge detection, Convolve con kernel, dilate, erode, histogram. Decodifica solo con códecs de Rust puro, con límite de píxeles.
R12 — Plot con plotters: line, bar, scatter, area, pie, histogram, candlestick, heatmap, polar, error bars, superficie y dispersión 3D. Datos de AddPoint o de una tabla COBOL (SetSeriesFromTable: recuento, stride y tipo numérico descritos una vez, valores leídos en una pasada, WASM-017 R11). Títulos, ejes, leyendas, cuadrículas y estilos. Render en un Canvas2D, en un ImageBuffer o como texto SVG.
Entrada, frames y accesibilidad
R13 — Los controles canvas pueden recibir el foco y entregan teclado, puntero, rueda, tacto y gamepad como eventos y como estado consultable (IsKeyDown, PointerX, PointerY, GamepadAxis, GamepadButton); exponen AccessibleLabel y una descripción para la tecnología de asistencia; el programa puede definir una alternativa de texto.
R14 — Con TargetFps por encima de cero, el canvas dispara onFrame a esa frecuencia con el tiempo transcurrido, sincronizado con la pantalla (requestAnimationFrame en el navegador, repaint de egui en desktop). Se pausa cuando la página o ventana está oculta y limita la frecuencia con batería baja. El modo fixed-step proporciona a un juego un onFrame estable para la física.
Seguridad y límites
R15 — Límites (tamaño del canvas, píxeles decodificados, tamaño del modelo y la textura, nodos y cuerpos, longitud de la lista de visualización), definidos por el proyecto con valores predeterminados seguros; al superarlos, error legible. No leen archivos ni abren conexiones (recursos incorporados; el acceso remoto pasa por el backend). Decodificación de imágenes y modelos no confiables con códecs de Rust puro, sometidos a fuzzing (WASM-013 R15). Un shader o modelo no provoca la caída de la página; la pérdida del dispositivo gráfico se gestiona y se notifica.
Plataformas
R16 — Todo host que ejecuta formularios implementa los controles y objetos: el host de formularios egui (Preview del IDE, Run Form, aplicaciones compiladas), donde Canvas2D envía píxeles como textura y Canvas3D renderiza en una textura; y el player (Web y Mobile). El intérprete y el módulo generado implementan los métodos y construyen la lista de visualización (WASM-010 R7). La paridad intérprete/binario se aplica a todos.
R17 — Form Designer muestra los canvas como marcadores de posición etiquetados con el tamaño y el backend. Preview, Run Form y la aplicación construida muestran el dibujo en vivo.
R18 — El player carga el motor 3D, el código de gráficos de datos y los filtros de imagen como partes en el primer uso (WASM-016 R13, WASM-017 R3). Build informa de los tamaños.
R19 — El proyecto de ejemplo examples/PowerGraphics acompaña al producto con un juego (sprites, física, entrada), galería de gráficos, laboratorio de imágenes y visor 3D, construido y ejecutado en Desktop y Web en la suite. El capítulo del Developer’s Guide se escribe en release.
Determinismo y paralelismo
R20 — El trabajo con Rayon (filtros y remuestreo, renderizado de gráficos, división del canvas en bloques, fase amplia de física) produce el mismo resultado con cualquier número de hilos, incluido uno: el trabajo por píxel es independiente, las reducciones siguen un orden fijo y la física utiliza enhanced-determinism. Las pruebas comparan un hilo frente a varios y plain frente a threaded; las imágenes de referencia son exactas para el rasterizador CPU y están dentro de una tolerancia declarada para la GPU.
Objetivos: Canvas2D y Canvas3D más ImageBuffer, Plot, Scene3D, Physics2D y Physics3D en Desktop, Web y Mobile, con la misma API y los mismos resultados; implementaciones 100 % Rust de crates populares; lista de visualización que mantiene la granularidad gruesa de la frontera; todos los núcleos cuando la plataforma los ofrece, con resultados idénticos cuando no; proyecto de ejemplo que ejercita todo.
Fuera del alcance: audio (desktop ya reproduce sonido mediante Animator); motor de juegos general (ECS, planificador, pipeline de recursos); renderizador 2D por GPU (la vía GPU sería un cambio interno); sustituir los siete controles de gráficos, PictureBox o Animator; ray tracing, compute shaders para el desarrollador, VR y AR.
Estado actual (§1): 62 tipos en ControlType::ALL; methods.rs exige el nombre en el vocabulario cerrado, o se interpreta como subíndice; CALL … RETURNING devuelve un valor desde 2026-10-19 (así es como un handle vuelve a COBOL). Crates ya presentes en el árbol: tiny-skia, kurbo, ab_glyph, skrifa, image, wgpu, naga, glow. Ausentes: imageproc, glam, lyon, plotters, rapier, gltf, rustybuzz, cosmic-text.
|