8.1 KiB
8.1 KiB
AI Prompt: Convert V Language Specs to Rust Hero Models
Objective
Convert V language model specifications (.v
files) to Rust hero models that integrate with the heromodels framework. The generated Rust models should follow the established patterns for base data embedding, indexing, fluent builder APIs, and Rhai scripting integration.
V Language Input Structure Analysis
V Spec Patterns to Recognize:
- Module Declaration:
module circle
ormodule group
- Base Embedding:
core.Base
- represents the base model data - Index Fields: Fields marked with
@[index]
comments - Mutability: Fields declared with
pub mut:
- Enums:
pub enum Status { active, inactive, suspended }
- Nested Structs: Embedded configuration or related data structures
- Collections:
[]u32
,[]string
,map[string]string
- References:
u32
fields typically represent foreign key references
Example V Spec Structure:
module circle
import freeflowuniverse.herolib.hero.models.core
pub struct User {
core.Base
pub mut:
username string @[index] // Unique username
email []string @[index] // Multiple email addresses
status UserStatus // Enum reference
profile UserProfile // Nested struct
metadata map[string]string // Key-value pairs
}
pub enum UserStatus {
active
inactive
suspended
}
pub struct UserProfile {
pub mut:
full_name string
bio string
links map[string]string
}
Rust Hero Model Conversion Rules
1. File Structure and Imports
use heromodels_core::{Model, BaseModelData, IndexKey};
use heromodels_derive::model;
use rhai::CustomType;
use rhailib_derive::RhaiApi;
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
2. Base Data Embedding
- V:
core.Base
- Rust:
pub base_data: BaseModelData,
3. Index Field Conversion
- V:
field_name string @[index]
- Rust:
#[index] pub field_name: String,
4. Type Mappings
V Type | Rust Type |
---|---|
string |
String |
[]string |
Vec<String> |
[]u32 |
Vec<u32> |
u32 |
u32 |
u64 |
u64 |
f64 |
f64 |
bool |
bool |
map[string]string |
std::collections::HashMap<String, String> |
5. Struct Declaration Pattern
/// Documentation comment describing the model
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default, RhaiApi)]
pub struct ModelName {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub indexed_field: String,
pub regular_field: String,
pub optional_field: Option<String>,
pub nested_struct: NestedType,
pub collection: Vec<u32>,
pub metadata: std::collections::HashMap<String, String>,
}
6. Enum Conversion
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum UserStatus {
Active,
Inactive,
Suspended,
}
7. Fluent Builder Implementation
Every model must implement a fluent builder pattern:
impl ModelName {
/// Create a new instance
pub fn new(id: u32) -> Self {
Self {
base_data: BaseModelData::new(id),
indexed_field: String::new(),
regular_field: String::new(),
optional_field: None,
nested_struct: NestedType::new(),
collection: Vec::new(),
metadata: std::collections::HashMap::new(),
}
}
/// Set indexed field (fluent)
pub fn indexed_field(mut self, value: impl ToString) -> Self {
self.indexed_field = value.to_string();
self
}
/// Set regular field (fluent)
pub fn regular_field(mut self, value: impl ToString) -> Self {
self.regular_field = value.to_string();
self
}
/// Set optional field (fluent)
pub fn optional_field(mut self, value: impl ToString) -> Self {
self.optional_field = Some(value.to_string());
self
}
/// Set nested struct (fluent)
pub fn nested_struct(mut self, value: NestedType) -> Self {
self.nested_struct = value;
self
}
/// Add to collection (fluent)
pub fn add_to_collection(mut self, value: u32) -> Self {
self.collection.push(value);
self
}
/// Set entire collection (fluent)
pub fn collection(mut self, value: Vec<u32>) -> Self {
self.collection = value;
self
}
/// Add metadata entry (fluent)
pub fn add_metadata(mut self, key: impl ToString, value: impl ToString) -> Self {
self.metadata.insert(key.to_string(), value.to_string());
self
}
/// Build the final instance
pub fn build(self) -> Self {
self
}
}
8. Model Trait Implementation
impl Model for ModelName {
fn db_prefix() -> &'static str {
"modelname"
}
fn get_id(&self) -> u32 {
self.base_data.id
}
fn base_data_mut(&mut self) -> &mut BaseModelData {
&mut self.base_data
}
fn db_keys(&self) -> Vec<IndexKey> {
let mut keys = Vec::new();
// Add index keys for fields marked with #[index]
keys.push(IndexKey::new("indexed_field", &self.indexed_field));
// Add additional index keys as needed
keys
}
}
9. Nested Struct Builder Pattern
For embedded types, implement similar builder patterns:
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct NestedType {
pub field1: String,
pub field2: String,
}
impl NestedType {
pub fn new() -> Self {
Self {
field1: String::new(),
field2: String::new(),
}
}
pub fn field1(mut self, value: impl ToString) -> Self {
self.field1 = value.to_string();
self
}
pub fn field2(mut self, value: impl ToString) -> Self {
self.field2 = value.to_string();
self
}
pub fn build(self) -> Self {
self
}
}
Conversion Steps
-
Analyze V Spec Structure
- Identify the module name and main structs
- Note which fields are marked with
@[index]
- Identify nested structs and enums
- Map field types from V to Rust
-
Create Rust File Structure
- Add appropriate imports
- Convert enums first (they're often referenced by structs)
- Convert nested structs before main structs
-
Implement Main Struct
- Add
#[model]
macro and derives - Embed
BaseModelData
asbase_data
- Mark indexed fields with
#[index]
- Convert field types according to mapping table
- Add
-
Implement Builder Pattern
- Add
new(id: u32)
constructor - Add fluent setter methods for each field
- Handle optional fields appropriately
- Add collection manipulation methods
- Add
-
Implement Model Trait
- Define appropriate
db_prefix
- Implement required trait methods
- Add index keys for searchable fields
- Define appropriate
-
Add Documentation
- Document the struct and its purpose
- Document each field's meaning
- Add usage examples in comments
Example Usage After Conversion
let user = User::new(1)
.username("john_doe")
.add_email("john@example.com")
.add_email("john.doe@company.com")
.status(UserStatus::Active)
.profile(
UserProfile::new()
.full_name("John Doe")
.bio("Software developer")
.build()
)
.add_metadata("department", "engineering")
.build();
Notes and Best Practices
- Field Naming: Convert V snake_case to Rust snake_case (usually no change needed)
- Optional Fields: Use
Option<T>
for fields that may be empty in V - Collections: Always provide both
add_item
andset_collection
methods - Error Handling: Builder methods should not panic; use appropriate defaults
- Documentation: Include comprehensive documentation for public APIs
- Testing: Consider adding unit tests for builder patterns
- Validation: Add validation logic in builder methods if needed
File Organization
Place the converted Rust models in the appropriate subdirectory under heromodels/src/models/
based on the domain (e.g., user/
, finance/
, governance/
, etc.).