smithery.ai

rust-patterns

Rust patterns and conventions used in ECSdb

First seen Mar 21, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 5,937 B
  • docs SUMMARY.md 64 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

ECSdb Rust Patterns

This guide covers the Rust patterns and conventions used throughout ECSdb.

Error Handling

Error Types

Each crate defines its own error type:

use thiserror::Error;

#[derive(Debug, Error)]
pub enum StorageError {
    #[error("key not found")]
    NotFound,

    #[error("column family not found: {0}")]
    ColumnFamilyNotFound(String),

    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),

    #[error("backend error: {0}")]
    Backend(String),
}

pub type StorageResult<T> = Result<T, StorageError>;

Error Conversion

Use #[from] for automatic conversion:

#[derive(Debug, Error)]
pub enum QueryError {
    #[error("storage error: {0}")]
    Storage(#[from] StorageError),

    #[error("parse error: {0}")]
    Parse(String),
}

The ? Operator

Prefer ? over unwrap():

// Good
fn process() -> Result<Value, Error> {
    let data = storage.get(key)?;
    let parsed = parse(data)?;
    Ok(transform(parsed))
}

// Bad
fn process() -> Value {
    let data = storage.get(key).unwrap();  // Panic risk!
    parse(data).unwrap()
}

Async Patterns

Async Traits

Use async-trait for async trait methods:

use async_trait::async_trait;

#[async_trait]
pub trait StorageEngine: Send + Sync {
    async fn get(&self, cf: &str, key: &[u8]) -> Result<Option<Vec<u8>>>;
    async fn put(&self, cf: &str, key: &[u8], value: &[u8]) -> Result<()>;
}

Spawning Tasks

Use tokio for async runtime:

use tokio::spawn;

async fn background_work() {
    spawn(async move {
        // Background task
    });
}

Serialization

MessagePack for Data

Use rmp-serde for efficient binary serialization:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct ComponentData {
    pub entity_id: Uuid,
    pub version: u64,
    pub data: Vec<u8>,
}

impl ComponentData {
    pub fn to_bytes(&self) -> Vec<u8> {
        rmp_serde::to_vec(self).expect("serialization should not fail")
    }

    pub fn from_bytes(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
        rmp_serde::from_slice(bytes)
    }
}

JSON for Queries

Use serde_json for query parsing:

use serde_json::Value;

pub fn parse_query(json: &str) -> Result<QueryAst, ParseError> {
    let value: Value = serde_json::from_str(json)?;
    // Parse into AST
}

Type Patterns

Newtype Pattern

Wrap primitive types for type safety:

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EntityId(pub Uuid);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ComponentTypeId(pub u32);

impl ComponentTypeId {
    pub fn from_name(name: &str) -> Self {
        use std::hash::{Hash, Hasher};
        let mut hasher = std::collections::hash_map::DefaultHasher::new();
        name.hash(&mut hasher);
        Self(hasher.finish() as u32)
    }
}

Builder Pattern

For complex configuration:

pub struct ConfigBuilder {
    data_dir: PathBuf,
    cache_size: usize,
}

impl ConfigBuilder {
    pub fn new(data_dir: PathBuf) -> Self {
        Self {
            data_dir,
            cache_size: 256 * 1024 * 1024,  // Default 256MB
        }
    }

    pub fn cache_size(mut self, size: usize) -> Self {
        self.cache_size = size;
        self
    }

    pub fn build(self) -> Config {
        Config {
            data_dir: self.data_dir,
            cache_size: self.cache_size,
        }
    }
}

Testing Patterns

Test Organization

#[cfg(test)]
mod tests {
    use super::*;

    // Test fixtures
    fn create_test_entity() -> Entity {
        Entity::new(Uuid::new_v4())
    }

    // Unit tests
    #[test]
    fn test_entity_creation() {
        let entity = create_test_entity();
        assert!(entity.id != Uuid::nil());
    }

    // Async tests
    #[tokio::test]
    async fn test_async_operation() {
        let result = async_fn().await;
        assert!(result.is_ok());
    }
}

Test Helpers

Create helper modules for common test utilities:

// tests/common/mod.rs
pub fn setup_test_db() -> TestDb {
    let temp_dir = TempDir::new().unwrap();
    TestDb::new(temp_dir)
}

pub struct TestDb {
    _temp_dir: TempDir,  // Keep alive
    pub engine: FjallStorageEngine,
}

Concurrency Patterns

Thread Safety

Use Arc for shared ownership, RwLock for interior mutability:

use std::sync::{Arc, RwLock};

pub struct Manager {
    state: Arc<RwLock<State>>,
}

impl Manager {
    pub fn read_state(&self) -> impl Deref<Target = State> + '_ {
        self.state.read().unwrap()
    }

    pub fn write_state(&self) -> impl DerefMut<Target = State> + '_ {
        self.state.write().unwrap()
    }
}

Atomic Operations

For simple counters and flags:

use std::sync::atomic::{AtomicU64, Ordering};

pub struct TransactionManager {
    next_xid: AtomicU64,
}

impl TransactionManager {
    pub fn allocate_xid(&self) -> u64 {
        self.next_xid.fetch_add(1, Ordering::SeqCst)
    }
}

Documentation Patterns

Module Documentation

//! # Storage Engine
//!
//! This module provides the storage abstraction layer for ECSdb.
//!
//! ## Overview
//!
//! The storage engine uses fjall as the underlying LSM-tree.
//!
//! ## Example
//!
//! ```rust
//! let engine = FjallStorageEngine::open(config)?;
//! engine.put("cf", b"key", b"value").await?;
//! ```

Item Documentation

/// A single component attached to an entity.
///
/// Components are stored in per-type column families with versioning
/// for temporal queries.
///
/// # Example
///
/// ```rust
/// let component = ComponentData::new(entity_id, "Position", data, 1, txn_id);
/// ```
pub struct ComponentData {
    /// The entity this component belongs to
    pub entity_id: Uuid,
    // ...
}