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; } 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 } } #[derive(Debug, Default)] pub struct NoopTelemetryPlatform; impl TelemetryPlatform for NoopTelemetryPlatform {} pub trait RuntimePlatform { fn display_size(&self) -> (usize, usize) { (480, 270) } 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 AudioBridge; fn audio_mut(&mut self) -> &mut dyn AudioBridge; fn input(&self) -> &dyn InputPlatform; fn input_mut(&mut self) -> &mut dyn InputPlatform; fn assets(&self) -> &dyn AssetBridge; fn assets_mut(&mut self) -> &mut dyn AssetBridge; 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() } } #[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"); } }