implements PLN-0098

This commit is contained in:
bQUARKz 2026-06-15 05:43:27 +01:00
parent 80a36a3e7a
commit 9b03d13a0a
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
3 changed files with 147 additions and 0 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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<T: AudioBridge + ?Sized> 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<T: AssetBridge + ?Sized> AssetStoragePlatform for T {}
pub trait ClockPacingPlatform {}
pub trait TelemetryPlatform {
fn telemetry_snapshot(&self) -> Option<TelemetryFrame> {
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<T: RuntimePlatform + ?Sized> 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");
}
}