From 9b03d13a0a54cb93c28966a0be879fc9ba5fa959 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Mon, 15 Jun 2026 05:43:27 +0100 Subject: [PATCH] implements PLN-0098 --- .../prometeu-hal/src/hardware_bridge.rs | 5 + crates/console/prometeu-hal/src/lib.rs | 6 + crates/console/prometeu-hal/src/platform.rs | 136 ++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 crates/console/prometeu-hal/src/platform.rs diff --git a/crates/console/prometeu-hal/src/hardware_bridge.rs b/crates/console/prometeu-hal/src/hardware_bridge.rs index fc06d80c..6b39c911 100644 --- a/crates/console/prometeu-hal/src/hardware_bridge.rs +++ b/crates/console/prometeu-hal/src/hardware_bridge.rs @@ -6,6 +6,11 @@ use crate::render_submission::{Game2DFramePacket, RenderSubmission}; use crate::sprite::Sprite; use crate::touch_bridge::TouchBridge; +/// Legacy migration scaffold for code that has not moved to `platform` facades yet. +/// +/// `HardwareBridge` is intentionally not the final runtime-facing contract. New +/// platform boundaries belong in `crate::platform`, and this trait must be +/// removed after runtime, firmware, host, and tests finish migrating. pub trait HardwareBridge { fn begin_frame(&mut self); fn bind_scene(&mut self, scene_bank_id: usize) -> bool; diff --git a/crates/console/prometeu-hal/src/lib.rs b/crates/console/prometeu-hal/src/lib.rs index fdd14e47..70067fa1 100644 --- a/crates/console/prometeu-hal/src/lib.rs +++ b/crates/console/prometeu-hal/src/lib.rs @@ -19,6 +19,7 @@ pub mod log; pub mod native_helpers; pub mod native_interface; pub mod pad_bridge; +pub mod platform; pub mod primitives; pub mod render_submission; pub mod sample; @@ -46,6 +47,11 @@ pub use input_signals::InputSignals; pub use native_helpers::{expect_bool, expect_int}; pub use native_interface::{NativeInterface, SyscallId}; pub use pad_bridge::PadBridge; +pub use platform::{ + AssetStoragePlatform, AudioPlatform, ClockPacingPlatform, Game2DFrameComposer, InputPlatform, + RenderBackend, RenderSubmissionSink, RenderSubmitError, RuntimePlatform, TelemetryPlatform, + TestPlatform, +}; pub use render_submission::{ BoundScenePacket, Camera2D, ComposerFramePacket, FrameId, Game2DFramePacket, GameSpritePacket, Gfx2dCommand, GfxUiCommand, HudCommand, HudPacket, RenderOwnership, RenderSubmission, diff --git a/crates/console/prometeu-hal/src/platform.rs b/crates/console/prometeu-hal/src/platform.rs new file mode 100644 index 00000000..0cd8d3fc --- /dev/null +++ b/crates/console/prometeu-hal/src/platform.rs @@ -0,0 +1,136 @@ +use crate::asset_bridge::AssetBridge; +use crate::audio_bridge::AudioBridge; +use crate::composer_status::ComposerOpStatus; +use crate::pad_bridge::PadBridge; +use crate::render_submission::{Game2DFramePacket, RenderSubmission}; +use crate::sprite::Sprite; +use crate::telemetry::TelemetryFrame; +use crate::touch_bridge::TouchBridge; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RenderSubmitError { + BackendUnavailable, + SubmissionRejected, +} + +pub trait RenderSubmissionSink { + fn submit_render_submission( + &mut self, + submission: RenderSubmission, + ) -> Result<(), RenderSubmitError>; +} + +pub trait RenderBackend { + fn render_frame(&mut self); +} + +pub trait Game2DFrameComposer { + fn begin_frame(&mut self); + fn bind_scene(&mut self, scene_bank_id: usize) -> ComposerOpStatus; + fn unbind_scene(&mut self); + fn set_camera(&mut self, x: i32, y: i32) -> ComposerOpStatus; + fn emit_sprite(&mut self, sprite: Sprite) -> ComposerOpStatus; + fn close_game2d_packet(&self) -> Game2DFramePacket; + fn has_glyph_bank(&self, bank_id: usize) -> bool; +} + +pub trait AudioPlatform: AudioBridge {} +impl AudioPlatform for T {} + +pub trait InputPlatform { + fn pad(&self) -> &dyn PadBridge; + fn pad_mut(&mut self) -> &mut dyn PadBridge; + fn touch(&self) -> &dyn TouchBridge; + fn touch_mut(&mut self) -> &mut dyn TouchBridge; +} + +pub trait AssetStoragePlatform: AssetBridge {} +impl AssetStoragePlatform for T {} + +pub trait ClockPacingPlatform {} + +pub trait TelemetryPlatform { + fn telemetry_snapshot(&self) -> Option { + None + } +} + +pub trait RuntimePlatform { + fn render_submission_sink(&mut self) -> &mut dyn RenderSubmissionSink; + fn render_backend(&mut self) -> &mut dyn RenderBackend; + fn game2d_frame_composer(&mut self) -> &mut dyn Game2DFrameComposer; + fn audio(&self) -> &dyn AudioPlatform; + fn audio_mut(&mut self) -> &mut dyn AudioPlatform; + fn input(&self) -> &dyn InputPlatform; + fn input_mut(&mut self) -> &mut dyn InputPlatform; + fn assets(&self) -> &dyn AssetStoragePlatform; + fn assets_mut(&mut self) -> &mut dyn AssetStoragePlatform; + fn telemetry(&self) -> &dyn TelemetryPlatform; +} + +pub trait TestPlatform: RuntimePlatform {} +impl TestPlatform for T {} + +#[cfg(test)] +mod tests { + use super::*; + + fn assert_render_sink_object(_: &mut dyn RenderSubmissionSink) {} + fn assert_backend_object(_: &mut dyn RenderBackend) {} + fn assert_composer_object(_: &mut dyn Game2DFrameComposer) {} + + struct CompileOnly; + + impl RenderSubmissionSink for CompileOnly { + fn submit_render_submission( + &mut self, + _submission: RenderSubmission, + ) -> Result<(), RenderSubmitError> { + Ok(()) + } + } + + impl RenderBackend for CompileOnly { + fn render_frame(&mut self) {} + } + + impl Game2DFrameComposer for CompileOnly { + fn begin_frame(&mut self) {} + + fn bind_scene(&mut self, _scene_bank_id: usize) -> ComposerOpStatus { + ComposerOpStatus::Ok + } + + fn unbind_scene(&mut self) {} + + fn set_camera(&mut self, _x: i32, _y: i32) -> ComposerOpStatus { + ComposerOpStatus::Ok + } + + fn emit_sprite(&mut self, _sprite: Sprite) -> ComposerOpStatus { + ComposerOpStatus::Ok + } + + fn close_game2d_packet(&self) -> Game2DFramePacket { + Game2DFramePacket::default() + } + + fn has_glyph_bank(&self, _bank_id: usize) -> bool { + false + } + } + + #[test] + fn core_platform_facades_are_object_safe() { + let mut compile_only = CompileOnly; + + assert_render_sink_object(&mut compile_only); + assert_backend_object(&mut compile_only); + assert_composer_object(&mut compile_only); + } + + #[test] + fn render_submit_error_is_typed_and_debuggable() { + assert_eq!(format!("{:?}", RenderSubmitError::BackendUnavailable), "BackendUnavailable"); + } +}