aboutsummaryrefslogtreecommitdiff
path: root/adapters/fparkan-platform-sdl
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-06-22 12:12:27 +0300
committerValentin Popov <valentin@popov.link>2026-06-22 12:13:32 +0300
commitd0bdbaa1ed76dfbf3211bb43eee48c49cc4fd448 (patch)
treea0bd35c3940be62a5b5de1acc2366af377ffd181 /adapters/fparkan-platform-sdl
parent7416fdc7e9a48837fff5056e6dc8d0774e90964b (diff)
downloadfparkan-d0bdbaa1ed76dfbf3211bb43eee48c49cc4fd448.tar.xz
fparkan-d0bdbaa1ed76dfbf3211bb43eee48c49cc4fd448.zip
feat: implement FParkan architecture foundation
Add the modular fparkan workspace, domain crates, adapters, apps, xtask policy/CI, acceptance evidence, and licensed corpus gates for the macOS-focused roadmap foundation.
Diffstat (limited to 'adapters/fparkan-platform-sdl')
-rw-r--r--adapters/fparkan-platform-sdl/Cargo.toml12
-rw-r--r--adapters/fparkan-platform-sdl/src/lib.rs123
2 files changed, 135 insertions, 0 deletions
diff --git a/adapters/fparkan-platform-sdl/Cargo.toml b/adapters/fparkan-platform-sdl/Cargo.toml
new file mode 100644
index 0000000..fd9b040
--- /dev/null
+++ b/adapters/fparkan-platform-sdl/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "fparkan-platform-sdl"
+version.workspace = true
+edition.workspace = true
+license.workspace = true
+repository.workspace = true
+
+[dependencies]
+fparkan-platform = { path = "../../crates/fparkan-platform" }
+
+[lints]
+workspace = true
diff --git a/adapters/fparkan-platform-sdl/src/lib.rs b/adapters/fparkan-platform-sdl/src/lib.rs
new file mode 100644
index 0000000..73aea1f
--- /dev/null
+++ b/adapters/fparkan-platform-sdl/src/lib.rs
@@ -0,0 +1,123 @@
+#![forbid(unsafe_code)]
+//! SDL platform adapter proof behind safe `FParkan` ports.
+
+use fparkan_platform::{
+ EventSource, GraphicsContextRequest, GraphicsProfile, PhysicalSize, PlatformError,
+ PlatformEvent, Version, WindowPort,
+};
+
+/// Adapter capabilities compiled into this package.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct SdlAdapterCapabilities {
+ /// Supported graphics context requests in preference order.
+ pub graphics: Vec<GraphicsContextRequest>,
+ /// Whether adapter-owned code is free of `unsafe`.
+ pub project_owned_unsafe_free: bool,
+}
+
+impl Default for SdlAdapterCapabilities {
+ fn default() -> Self {
+ Self {
+ graphics: vec![
+ GraphicsContextRequest {
+ profile: GraphicsProfile::DesktopCore,
+ version: Version { major: 3, minor: 3 },
+ },
+ GraphicsContextRequest {
+ profile: GraphicsProfile::Embedded,
+ version: Version { major: 2, minor: 0 },
+ },
+ ],
+ project_owned_unsafe_free: true,
+ }
+ }
+}
+
+/// Returns adapter readiness status for the safe project-owned layer.
+#[must_use]
+pub fn safe_adapter_ready() -> bool {
+ SdlAdapterCapabilities::default().project_owned_unsafe_free
+}
+
+/// In-memory event source used by adapter smoke tests and composition roots
+/// before a concrete SDL runtime is injected.
+#[derive(Clone, Debug, Default)]
+pub struct SdlEventSourceProof {
+ pending: Vec<PlatformEvent>,
+}
+
+impl SdlEventSourceProof {
+ /// Creates an event source with deterministic pending events.
+ #[must_use]
+ pub fn new(pending: Vec<PlatformEvent>) -> Self {
+ Self { pending }
+ }
+}
+
+impl EventSource for SdlEventSourceProof {
+ fn poll(&mut self, out: &mut Vec<PlatformEvent>) -> Result<(), PlatformError> {
+ out.append(&mut self.pending);
+ Ok(())
+ }
+}
+
+/// Safe window-port proof with SDL-compatible drawable-size semantics.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct SdlWindowProof {
+ size: PhysicalSize,
+ presents: u64,
+}
+
+impl SdlWindowProof {
+ /// Creates a proof window with a fixed drawable size.
+ #[must_use]
+ pub fn new(size: PhysicalSize) -> Self {
+ Self { size, presents: 0 }
+ }
+
+ /// Number of successful present calls.
+ #[must_use]
+ pub fn presents(&self) -> u64 {
+ self.presents
+ }
+}
+
+impl WindowPort for SdlWindowProof {
+ fn drawable_size(&self) -> PhysicalSize {
+ self.size
+ }
+
+ fn present(&mut self) -> Result<(), PlatformError> {
+ self.presents = self.presents.saturating_add(1);
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn adapter_reports_safe_project_layer_ready() {
+ assert!(safe_adapter_ready());
+ assert_eq!(SdlAdapterCapabilities::default().graphics.len(), 2);
+ }
+
+ #[test]
+ fn event_source_and_window_ports_are_deterministic() -> Result<(), PlatformError> {
+ let mut source = SdlEventSourceProof::new(vec![PlatformEvent::Quit]);
+ let mut events = Vec::new();
+ source.poll(&mut events)?;
+ source.poll(&mut events)?;
+ assert_eq!(events, vec![PlatformEvent::Quit]);
+
+ let mut window = SdlWindowProof::new(PhysicalSize {
+ width: 320,
+ height: 240,
+ });
+ assert_eq!(window.drawable_size().width, 320);
+ window.present()?;
+ assert_eq!(window.presents(), 1);
+ Ok(())
+ }
+}