7.1 KiB
7.1 KiB
OSIRIS Code Structure
📁 Directory Organization
Objects (src/objects/)
Each OSIRIS object has its own directory with:
mod.rs- Object definition and core logicrhai.rs- Rhai integration (CustomType, builder API)
src/objects/
├── mod.rs # Module exports
├── note/
│ ├── mod.rs # Note object definition
│ └── rhai.rs # Note Rhai integration
└── event/
├── mod.rs # Event object definition
└── rhai.rs # Event Rhai integration
Rhai Support (src/rhai_support/)
Core Rhai infrastructure (not object-specific):
instance.rs- OsirisInstance type for multi-instance supportmod.rs- Module exports and re-exports
src/rhai_support/
├── mod.rs # Re-exports from object modules
└── instance.rs # OsirisInstance implementation
Runner (src/bin/runner/)
Standalone binary for running OSIRIS scripts:
main.rs- CLI and script executionengine.rs- Engine factory with instance configuration
src/bin/runner/
├── main.rs # CLI interface
└── engine.rs # Engine configuration
Core (src/)
Core OSIRIS functionality:
store/- GenericStore, HeroDbClient, BaseDataindex/- Field indexingerror/- Error typesconfig/- Configurationinterfaces/- Traits and interfacesretrieve/- Retrieval logic
🎯 Design Principles
1. Co-location
Object-specific code lives with the object:
objects/note/
├── mod.rs # Note struct, impl
└── rhai.rs # Note Rhai support
2. Separation of Concerns
- Objects - Domain models and business logic
- Rhai Support - Scripting integration
- Store - Persistence layer
- Runner - Execution environment
3. Feature Gating
Rhai support is optional via rhai-support feature:
#[cfg(feature = "rhai-support")]
pub mod rhai;
4. Clean Exports
Clear module boundaries with re-exports:
// src/objects/mod.rs
pub mod note;
pub use note::Note;
// src/rhai_support/mod.rs
pub use crate::objects::note::rhai::register_note_api;
📝 Adding a New Object
1. Create Object Directory
mkdir -p src/objects/task
2. Create Object Definition (mod.rs)
use crate::store::BaseData;
use serde::{Deserialize, Serialize};
#[cfg(feature = "rhai-support")]
pub mod rhai;
#[derive(Debug, Clone, Serialize, Deserialize, crate::DeriveObject)]
pub struct Task {
pub base_data: BaseData,
#[index]
pub title: String,
pub completed: bool,
}
impl Task {
pub fn new(ns: String) -> Self {
Self {
base_data: BaseData::new(ns),
title: String::new(),
completed: false,
}
}
}
3. Create Rhai Integration (rhai.rs)
use crate::objects::Task;
use rhai::{CustomType, Engine, TypeBuilder};
impl CustomType for Task {
fn build(mut builder: TypeBuilder<Self>) {
builder
.with_name("Task")
.with_fn("new", |ns: String| Task::new(ns))
.with_fn("set_title", |task: &mut Task, title: String| {
task.title = title;
task.base_data.update_modified();
})
.with_fn("set_completed", |task: &mut Task, completed: bool| {
task.completed = completed;
task.base_data.update_modified();
});
}
}
pub fn register_task_api(engine: &mut Engine) {
engine.build_type::<Task>();
// Builder pattern
engine.register_fn("task", |ns: String| Task::new(ns));
engine.register_fn("title", |mut task: Task, title: String| {
task.title = title;
task.base_data.update_modified();
task
});
engine.register_fn("completed", |mut task: Task, completed: bool| {
task.completed = completed;
task.base_data.update_modified();
task
});
}
4. Update Module Exports
// src/objects/mod.rs
pub mod task;
pub use task::Task;
// src/rhai_support/mod.rs
pub use crate::objects::task::rhai::register_task_api;
5. Register in Engine
// src/bin/runner/engine.rs
use osiris::rhai_support::register_task_api;
register_task_api(&mut engine);
6. Use in Scripts
let my_task = task("tasks")
.title("Complete OSIRIS integration")
.completed(true);
my_instance.put_task(my_task);
🔍 File Responsibilities
Object mod.rs
- Struct definition with
#[derive(DeriveObject)] - Index fields marked with
#[index] - Constructor methods (
new,with_id) - Business logic methods
- Builder pattern methods (optional)
Object rhai.rs
CustomTypeimplementationregister_*_apifunction- Rhai-specific builder methods
- Type conversions for Rhai
rhai_support/instance.rs
OsirisInstancestruct- Multi-instance support
- CRUD operations per instance
- Async → Sync bridge
bin/runner/engine.rs
OsirisConfigfor instance configurationcreate_osiris_engine_with_configfunction- Engine setup and registration
bin/runner/main.rs
- CLI argument parsing
- Instance configuration from CLI
- Script loading and execution
🎨 Benefits of This Structure
1. Discoverability
All code for an object is in one place:
objects/note/
├── mod.rs # "What is a Note?"
└── rhai.rs # "How do I use Note in Rhai?"
2. Maintainability
Changes to an object are localized:
- Add a field → Update
mod.rsandrhai.rs - No hunting through multiple directories
3. Scalability
Easy to add new objects:
- Create directory
- Add two files
- Update exports
- Done!
4. Testability
Each object can have its own tests:
objects/note/
├── mod.rs
├── rhai.rs
└── tests.rs
5. Clear Dependencies
Objects (domain) → Independent
↓
Rhai Support → Depends on Objects
↓
Runner → Depends on Rhai Support
📊 Module Graph
osiris (lib)
├── objects/
│ ├── note/
│ │ ├── mod.rs (Note struct)
│ │ └── rhai.rs (Note Rhai)
│ └── event/
│ ├── mod.rs (Event struct)
│ └── rhai.rs (Event Rhai)
├── rhai_support/
│ ├── instance.rs (OsirisInstance)
│ └── mod.rs (re-exports)
├── store/ (GenericStore, BaseData)
├── index/ (FieldIndex)
└── error/ (Error types)
runner (bin)
├── main.rs (CLI)
└── engine.rs (Engine factory)
✅ Summary
Old Structure:
src/rhai_support/
├── note_rhai.rs
├── event_rhai.rs
├── engine.rs
└── instance.rs
New Structure:
src/objects/
├── note/
│ ├── mod.rs
│ └── rhai.rs
└── event/
├── mod.rs
└── rhai.rs
src/rhai_support/
├── instance.rs
└── mod.rs (re-exports only)
Benefits:
- ✅ Better organization
- ✅ Co-located code
- ✅ Easier to find things
- ✅ Cleaner separation
- ✅ Scalable structure