第6回:GennethleiaCore - コアフレームワーク
~no_std環境対応の基盤設計~
はじめに
GennethleiaCoreは、様々な環境で動作する基盤フレームワークです。no_std環境での動作と、プラットフォーム非依存の設計を中心に解説します。
no_std環境対応の基盤設計
// 基本的なメモリアロケータ
#[cfg(not(feature = "std"))]
pub struct CoreAllocator {
inner: linked_list_allocator::Heap,
}
#[cfg(not(feature = "std"))]
impl CoreAllocator {
pub const fn empty() -> Self {
Self {
inner: linked_list_allocator::Heap::empty(),
}
}
pub unsafe fn init(&mut self, start: *mut u8, size: usize) {
self.inner.init(start as usize, size);
}
}
#[cfg(not(feature = "std"))]
#[global_allocator]
static ALLOCATOR: CoreAllocator = CoreAllocator::empty();
// コアデータ構造
#[cfg(not(feature = "std"))]
pub mod collections {
use alloc::vec::Vec;
use alloc::collections::BTreeMap;
pub struct CoreVec<T> {
inner: Vec<T>,
}
impl<T> CoreVec<T> {
pub fn new() -> Self {
Self {
inner: Vec::new(),
}
}
pub fn push(&mut self, value: T) {
self.inner.push(value);
}
}
pub struct CoreMap<K, V> {
inner: BTreeMap<K, V>,
}
}
// プラットフォーム抽象化
pub trait Platform: Send + Sync {
fn allocate(&self, size: usize) -> Result<*mut u8>;
fn deallocate(&self, ptr: *mut u8, size: usize);
fn get_time(&self) -> Result<u64>;
fn sleep(&self, duration: u64) -> Result<()>;
}
共有可能ロジックの抽象化
// 共有ロジックの基本実装
pub trait SharedLogic: Send + Sync {
type Input;
type Output;
type Error;
fn execute(&self, input: Self::Input) -> Result<Self::Output, Self::Error>;
}
// ビジネスロジックの抽象化
pub struct CoreLogic<P: Platform> {
platform: P,
cache: Cache,
shared_state: SharedState,
}
impl<P: Platform> CoreLogic<P> {
pub fn new(platform: P) -> Self {
Self {
platform,
cache: Cache::new(),
shared_state: SharedState::new(),
}
}
pub fn with_cache_size(mut self, size: usize) -> Self {
self.cache = Cache::with_capacity(size);
self
}
}
// キャッシュシステム
pub struct Cache {
entries: CoreMap<CacheKey, CacheEntry>,
policy: Box<dyn CachePolicy>,
}
impl Cache {
pub fn insert(&mut self, key: CacheKey, value: CacheEntry) {
if self.policy.should_evict() {
if let Some(evict_key) = self.policy.select_evict() {
self.entries.remove(&evict_key);
}
}
self.entries.insert(key, value);
}
}
プラットフォーム非依存レイヤー
// プラットフォーム抽象化レイヤー
pub trait PlatformLayer: Send + Sync {
fn filesystem(&self) -> &dyn FileSystem;
fn network(&self) -> &dyn Network;
fn timer(&self) -> &dyn Timer;
fn logger(&self) -> &dyn Logger;
}
// ファイルシステム抽象化
pub trait FileSystem {
fn read(&self, path: &str) -> Result<Vec<u8>>;
fn write(&self, path: &str, data: &[u8]) -> Result<()>;
fn delete(&self, path: &str) -> Result<()>;
fn exists(&self, path: &str) -> Result<bool>;
}
// ネットワーク抽象化
pub trait Network {
fn connect(&self, address: &str) -> Result<Box<dyn Connection>>;
fn listen(&self, address: &str) -> Result<Box<dyn Listener>>;
}
pub trait Connection: Send + Sync {
fn send(&self, data: &[u8]) -> Result<usize>;
fn receive(&self, buffer: &mut [u8]) -> Result<usize>;
fn close(&self) -> Result<()>;
}
// タイマー抽象化
pub trait Timer {
fn now(&self) -> Result<u64>;
fn set_timeout(&self, duration: u64, callback: Box<dyn Fn() + Send>) -> Result<TimerId>;
fn cancel_timeout(&self, timer_id: TimerId) -> Result<()>;
}
実装例:クロスプラットフォームストレージの実装
// クロスプラットフォームストレージ
pub struct CoreStorage<P: Platform> {
platform: P,
serializer: Box<dyn Serializer>,
compression: Box<dyn Compression>,
}
impl<P: Platform> CoreStorage<P> {
pub async fn store<T: Serialize>(&self, key: &str, value: &T) -> Result<()> {
// シリアライズ
let bytes = self.serializer.serialize(value)?;
// 圧縮
let compressed = self.compression.compress(&bytes)?;
// プラットフォーム固有のストレージに保存
self.store_raw(key, &compressed).await
}
pub async fn load<T: DeserializeOwned>(&self, key: &str) -> Result<T> {
// プラットフォーム固有のストレージから読み込み
let compressed = self.load_raw(key).await?;
// 解凍
let bytes = self.compression.decompress(&compressed)?;
// デシリアライズ
self.serializer.deserialize(&bytes)
}
}
// プラットフォーム固有の実装例
#[cfg(feature = "std")]
pub struct StdPlatform {
fs: std::fs::File,
}
#[cfg(not(feature = "std"))]
pub struct NoStdPlatform {
flash: embedded_storage::Flash,
}
impl Platform for StdPlatform {
fn store_raw(&self, key: &str, data: &[u8]) -> Result<()> {
std::fs::write(key, data)
}
fn load_raw(&self, key: &str) -> Result<Vec<u8>> {
std::fs::read(key)
}
}
impl Platform for NoStdPlatform {
fn store_raw(&self, key: &str, data: &[u8]) -> Result<()> {
self.flash.write(key.as_bytes(), data)
}
fn load_raw(&self, key: &str) -> Result<Vec<u8>> {
self.flash.read(key.as_bytes())
}
}
// 使用例
async fn store_data<P: Platform>(storage: &CoreStorage<P>) -> Result<()> {
let data = MyData {
id: 1,
name: "test",
};
storage.store("my_data", &data).await
}
今回のまとめ
- no_std環境での基盤実装
- プラットフォーム抽象化レイヤーの設計
- 共有可能なロジックの実装
- クロスプラットフォームストレージの実現
次回予告
第7回では、gennethleia-appのアプリケーションフレームワークについて解説します。ビジネスロジックの分離とプラグイン機構の実装について詳しく見ていきます。
参考資料
- Embedded Rust Programming
- Cross-Platform Development Patterns
- No-STD Rust Programming
- Platform Abstraction Design Patterns