use aethellib::{engine::combinators, prelude::*};
use rand::{Rng, RngExt};
struct BladeCodeRule {
pool: PoolRef,
}
impl BladeCodeRule {
fn new(pool: PoolRef) -> Self {
Self { pool }
}
}
impl Rule for BladeCodeRule {
fn pool_refs(&self) -> Vec<PoolRef> {
vec![self.pool.clone()]
}
fn execute<'a>(
&self,
ctx: &GenerationContext<'a>,
rng: &mut dyn Rng,
) -> Result<ComposedValue, AethelError> {
let values = ctx
.corpus
.pooled_values_for_field_section(self.pool.field(), self.pool.section())
.ok_or_else(|| AethelError::PoolNotFound {
section: self.pool.section().to_string(),
field: self.pool.field().to_string(),
})?;
if values.is_empty() {
return Err(AethelError::Custom("pool is empty".to_string()));
}
let left = &values[rng.random_range(0..values.len())];
let right = &values[rng.random_range(0..values.len())];
Ok(ComposedValue {
value: format!(
"{}-{}",
left.value.to_uppercase(),
right.value.to_uppercase()
),
provenance: left
.provenance
.iter()
.chain(&right.provenance)
.cloned()
.collect(),
})
}
}
fn main() {
let corpus = Corpus::from_files(
&["examples/data/weapon_test_data.toml"],
"weapon",
None,
None,
)
.expect("failed to load weapon corpus");
let blade_code = RuleKey::new("blade_code").expect("rule key should be valid");
let weapon_kind = RuleKey::new("weapon_kind").expect("rule key should be valid");
let display = RuleKey::new("display").expect("rule key should be valid");
let primitives = PoolRef::new("name", "primitives").expect("pool ref should be valid");
let kind = PoolRef::new("type", "type").expect("pool ref should be valid");
let compiled = PlanBuilder::new(&corpus)
.rule(&blade_code, BladeCodeRule::new(primitives))
.rule(&weapon_kind, combinators::pick(kind))
.rule(
&display,
combinators::custom(
[blade_code.clone(), weapon_kind.clone()],
|ctx, _rng, deps| {
let code = ctx.require(&deps[0])?;
let kind = ctx.require(&deps[1])?;
Ok(ComposedValue {
value: format!("{} {}", code.value, kind.value),
provenance: code
.provenance
.iter()
.chain(&kind.provenance)
.cloned()
.collect(),
})
},
),
)
.validate()
.expect("plan validation failed")
.compile()
.expect("plan compilation failed");
let mut rng = rand::rng();
let ctx = compiled.generate(&mut rng).expect("generation failed");
println!(
"Generated custom weapon: {}",
ctx.require(&display).expect("display should exist").value,
);
}