//! Phase 88: Ring0Context - OS API 抽象化レイヤー //! //! Ring0 は Box を知らない、Nyash を知らない純粋な OS API 層。 mod errors; mod std_impls; mod traits; pub use errors::{IoError, TimeError}; pub use std_impls::{NoFsApi, NoopMem, StdFs, StdIo, StdLog, StdMem, StdThread, StdTime}; pub use traits::{ FsApi, FsMetadata, IoApi, LogApi, LogLevel, MemApi, MemStats, ThreadApi, TimeApi, }; use crate::runtime::runtime_profile::RuntimeProfile; use std::sync::{Arc, OnceLock}; /// Phase 88: Ring0 コンテキスト /// /// OS API レイヤーを trait で抽象化し、1つの構造体に束ねる。 pub struct Ring0Context { pub mem: Arc, pub io: Arc, pub time: Arc, pub log: Arc, pub fs: Arc, // Phase 90-A pub thread: Arc, // Phase 90-D } impl Ring0Context { /// 新規 Ring0Context を作成 pub fn new( mem: Arc, io: Arc, time: Arc, log: Arc, fs: Arc, thread: Arc, ) -> Self { Self { mem, io, time, log, fs, thread, } } } impl std::fmt::Debug for Ring0Context { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Ring0Context") .field("mem", &"") .field("io", &"") .field("time", &"") .field("log", &"") .field("fs", &"") .field("thread", &"") .finish() } } /// Phase 112: Ring0 service registry /// /// profile ごとに適切な FsApi 実装(等)を選択して Ring0Context を構築する factory。 pub struct Ring0Registry; impl Ring0Registry { /// Ring0Context を profile に応じて構築 pub fn build(profile: RuntimeProfile) -> Ring0Context { match profile { RuntimeProfile::Default => Self::build_with_fs(Arc::new(StdFs)), RuntimeProfile::NoFs => Self::build_with_fs(Arc::new(NoFsApi)), } } fn build_with_fs(fs: Arc) -> Ring0Context { Ring0Context { mem: Arc::new(StdMem::new()), io: Arc::new(StdIo), time: Arc::new(StdTime), log: Arc::new(StdLog), fs, thread: Arc::new(StdThread), } } } /// Phase 88: デフォルト Ring0Context を作成 /// /// Phase 112 以降は、initialize_runtime() を通じて /// Ring0Registry::build(profile) 経由で初期化されることが推奨。 /// /// この関数は直接呼び出しに対する互換性レイヤーとして保持。 pub fn default_ring0() -> Ring0Context { Ring0Registry::build(RuntimeProfile::Default) } // ===== グローバル Ring0Context ===== pub static GLOBAL_RING0: OnceLock> = OnceLock::new(); /// グローバル Ring0Context を初期化 pub fn init_global_ring0(ctx: Ring0Context) { GLOBAL_RING0 .set(Arc::new(ctx)) .expect("[Phase 88] Ring0Context already initialized"); } /// グローバル Ring0Context を取得 pub fn get_global_ring0() -> Arc { GLOBAL_RING0 .get() .expect("[Phase 88] Ring0Context not initialized") .clone() } // ===== テスト ===== #[cfg(test)] mod tests { use super::*; fn unsafe_dealloc(ptr: *mut u8, size: usize) { unsafe { std::alloc::dealloc(ptr, std::alloc::Layout::from_size_align_unchecked(size, 1)) } } #[test] fn test_ring0_context_creation() { let ring0 = default_ring0(); ring0.log.info("test message"); } #[test] fn test_io_api() { let ring0 = default_ring0(); let result = ring0.io.stdout_write(b"test\n"); assert!(result.is_ok()); } #[test] fn test_time_api() { let ring0 = default_ring0(); let now = ring0.time.now(); assert!(now.is_ok()); let instant = ring0.time.monotonic_now(); assert!(instant.is_ok()); } #[test] fn test_log_levels() { let ring0 = default_ring0(); ring0.log.debug("debug message"); ring0.log.info("info message"); ring0.log.warn("warn message"); ring0.log.error("error message"); } #[test] fn test_default_ring0_uses_stdmem() { let ring0 = default_ring0(); let ptr = ring0.mem.alloc(512); assert!(!ptr.is_null(), "default_ring0 should use StdMem"); ring0.mem.free(ptr); // Clean up unsafe_dealloc(ptr, 512); } // Phase 112: Ring0Registry tests #[test] fn test_ring0_registry_default_profile() { let ctx = Ring0Registry::build(RuntimeProfile::Default); // Verify basic operations work ctx.log.info("Test message from Default profile"); assert!(ctx.time.now().is_ok()); } #[test] fn test_ring0_registry_nofs_profile() { use std::path::Path; let ctx = Ring0Registry::build(RuntimeProfile::NoFs); // Verify NoFsApi returns errors let result = ctx.fs.read_to_string(Path::new("/tmp/test.txt")); assert!(result.is_err()); // Verify exists returns false assert!(!ctx.fs.exists(Path::new("/tmp/test.txt"))); // Other services should still work ctx.log.info("Test message from NoFs profile"); assert!(ctx.time.now().is_ok()); } #[test] fn test_default_ring0_uses_registry() { let ctx = default_ring0(); // Should behave same as Default profile ctx.log.info("Test from default_ring0()"); assert!(ctx.time.now().is_ok()); } #[test] fn test_nofs_api_read_to_string() { let api = NoFsApi; let result = api.read_to_string(std::path::Path::new("/tmp/test.txt")); assert!(result.is_err()); assert!(result.unwrap_err().to_string().contains("disabled")); } #[test] fn test_nofs_api_read() { let api = NoFsApi; assert!(api.read(std::path::Path::new("/tmp/test.txt")).is_err()); } #[test] fn test_nofs_api_write_all() { let api = NoFsApi; assert!(api .write_all(std::path::Path::new("/tmp/test.txt"), b"data") .is_err()); } #[test] fn test_nofs_api_append_all() { let api = NoFsApi; assert!(api .append_all(std::path::Path::new("/tmp/test.txt"), b"data") .is_err()); } #[test] fn test_nofs_api_exists() { let api = NoFsApi; assert!(!api.exists(std::path::Path::new("/tmp/test.txt"))); } #[test] fn test_nofs_api_metadata() { let api = NoFsApi; assert!(api.metadata(std::path::Path::new("/tmp/test.txt")).is_err()); } #[test] fn test_nofs_api_canonicalize() { let api = NoFsApi; assert!(api .canonicalize(std::path::Path::new("/tmp/test.txt")) .is_err()); } }