use crate::simulation::typed_executor::{ExecutionResult, LayoutInfo, StateMode, Value};
use crate::simulation::CustomIoChange;
use std::collections::HashMap;
pub(crate) fn positions_from_flat(flat: &[i32]) -> Vec<(i32, i32, i32)> {
flat.chunks_exact(3).map(|c| (c[0], c[1], c[2])).collect()
}
pub(crate) fn parse_state_mode(s: &str) -> Option<StateMode> {
match s.to_lowercase().as_str() {
"stateless" => Some(StateMode::Stateless),
"stateful" => Some(StateMode::Stateful),
"manual" => Some(StateMode::Manual),
_ => None,
}
}
pub(crate) fn parse_inputs_json(json: &str) -> Result<HashMap<String, Value>, String> {
let parsed: serde_json::Value =
serde_json::from_str(json).map_err(|e| format!("Invalid JSON: {}", e))?;
let obj = parsed
.as_object()
.ok_or_else(|| "Inputs must be a JSON object".to_string())?;
let mut inputs = HashMap::new();
for (name, val) in obj {
let value = parse_json_value(val)?;
inputs.insert(name.clone(), value);
}
Ok(inputs)
}
pub(crate) fn parse_json_value(v: &serde_json::Value) -> Result<Value, String> {
if let Some(obj) = v.as_object() {
if let (Some(type_val), Some(value_val)) = (obj.get("type"), obj.get("value")) {
if let Some(type_str) = type_val.as_str() {
return match type_str {
"u32" => {
let n = value_val
.as_u64()
.ok_or("Expected unsigned integer for u32")?;
Ok(Value::U32(n as u32))
}
"i32" => {
let n = value_val.as_i64().ok_or("Expected integer for i32")?;
Ok(Value::I32(n as i32))
}
"f32" => {
let n = value_val.as_f64().ok_or("Expected number for f32")?;
Ok(Value::F32(n as f32))
}
"bool" => {
let b = value_val.as_bool().ok_or("Expected boolean for bool")?;
Ok(Value::Bool(b))
}
"string" => {
let s = value_val.as_str().ok_or("Expected string for string")?;
Ok(Value::String(s.to_string()))
}
_ => Err(format!("Unknown value type: {}", type_str)),
};
}
}
}
match v {
serde_json::Value::Bool(b) => Ok(Value::Bool(*b)),
serde_json::Value::Number(n) => {
if let Some(i) = n.as_i64() {
if i >= 0 {
Ok(Value::U32(i as u32))
} else {
Ok(Value::I32(i as i32))
}
} else if let Some(f) = n.as_f64() {
Ok(Value::F32(f as f32))
} else {
Err("Cannot parse number".to_string())
}
}
serde_json::Value::String(s) => Ok(Value::String(s.clone())),
_ => Err(format!("Cannot convert JSON value to Value: {}", v)),
}
}
pub(crate) fn value_to_json(v: &Value) -> serde_json::Value {
match v {
Value::U32(n) => serde_json::json!({"type": "u32", "value": n}),
Value::U64(n) => serde_json::json!({"type": "u64", "value": n}),
Value::I32(n) => serde_json::json!({"type": "i32", "value": n}),
Value::I64(n) => serde_json::json!({"type": "i64", "value": n}),
Value::F32(n) => serde_json::json!({"type": "f32", "value": n}),
Value::Bool(b) => serde_json::json!({"type": "bool", "value": b}),
Value::String(s) => serde_json::json!({"type": "string", "value": s}),
Value::BitArray(bits) => serde_json::json!({"type": "bit_array", "value": bits}),
Value::Bytes(bytes) => serde_json::json!({"type": "bytes", "value": bytes}),
Value::Array(arr) => {
let vals: Vec<serde_json::Value> = arr.iter().map(value_to_json).collect();
serde_json::json!({"type": "array", "value": vals})
}
Value::Struct(fields) => {
let obj: serde_json::Map<String, serde_json::Value> = fields
.iter()
.map(|(k, v)| (k.clone(), value_to_json(v)))
.collect();
serde_json::json!({"type": "struct", "value": obj})
}
}
}
pub(crate) fn serialize_execution_result(result: &ExecutionResult) -> String {
let mut outputs = serde_json::Map::new();
for (name, value) in &result.outputs {
outputs.insert(name.clone(), value_to_json(value));
}
let json = serde_json::json!({
"outputs": outputs,
"ticks_elapsed": result.ticks_elapsed,
"condition_met": result.condition_met,
});
serde_json::to_string(&json).unwrap_or_else(|_| "{}".to_string())
}
pub(crate) fn serialize_layout_info(info: &LayoutInfo) -> String {
fn side(
map: &HashMap<String, crate::simulation::typed_executor::IoLayoutInfo>,
) -> serde_json::Value {
let mut out = serde_json::Map::new();
for (name, li) in map {
let positions: Vec<Vec<i32>> = li
.positions
.iter()
.map(|&(x, y, z)| vec![x, y, z])
.collect();
out.insert(
name.clone(),
serde_json::json!({
"io_type": li.io_type,
"positions": positions,
"bit_count": li.bit_count,
}),
);
}
serde_json::Value::Object(out)
}
let json = serde_json::json!({
"inputs": side(&info.inputs),
"outputs": side(&info.outputs),
});
serde_json::to_string(&json).unwrap_or_else(|_| "{}".to_string())
}
pub(crate) fn serialize_custom_io_changes(changes: &[CustomIoChange]) -> String {
let arr: Vec<serde_json::Value> = changes
.iter()
.map(|c| {
serde_json::json!({
"x": c.x,
"y": c.y,
"z": c.z,
"old_power": c.old_power,
"new_power": c.new_power,
})
})
.collect();
serde_json::to_string(&arr).unwrap_or_else(|_| "[]".to_string())
}
#[diplomat::bridge]
pub mod ffi {
use super::super::schematic::ffi::Schematic;
use super::super::shared::ffi::NucleationError;
use crate::definition_region::DefinitionRegion;
use crate::simulation::circuit_builder::CircuitBuilder as InnerCircuitBuilder;
use crate::simulation::typed_executor::{
ExecutionMode as InnerExecutionMode, IoLayout as InnerIoLayout,
IoLayoutBuilder as InnerIoLayoutBuilder, IoType as InnerIoType,
LayoutFunction as InnerLayoutFunction, OutputCondition as InnerOutputCondition,
SortStrategy as InnerSortStrategy, TypedCircuitExecutor as InnerTypedCircuitExecutor,
Value as InnerValue,
};
use crate::simulation::SimulationOptions;
use diplomat_runtime::DiplomatWrite;
use mchprs_blocks::BlockPos as MPos;
use std::fmt::Write;
#[diplomat::opaque_mut]
pub struct MchprsWorld(pub(crate) crate::simulation::MchprsWorld);
impl MchprsWorld {
pub fn create(schematic: &Schematic) -> Result<Box<MchprsWorld>, NucleationError> {
crate::simulation::MchprsWorld::new(schematic.0.clone())
.map(|w| Box::new(MchprsWorld(w)))
.map_err(|_| NucleationError::Simulation)
}
pub fn create_with_options(
schematic: &Schematic,
optimize: bool,
io_only: bool,
) -> Result<Box<MchprsWorld>, NucleationError> {
let options = SimulationOptions {
optimize,
io_only,
custom_io: Vec::new(),
};
crate::simulation::MchprsWorld::with_options(schematic.0.clone(), options)
.map(|w| Box::new(MchprsWorld(w)))
.map_err(|_| NucleationError::Simulation)
}
pub fn create_with_custom_io(
schematic: &Schematic,
optimize: bool,
io_only: bool,
custom_io_positions: &[i32],
) -> Result<Box<MchprsWorld>, NucleationError> {
let custom_io = custom_io_positions
.chunks_exact(3)
.map(|c| MPos::new(c[0], c[1], c[2]))
.collect();
let options = SimulationOptions {
optimize,
io_only,
custom_io,
};
crate::simulation::MchprsWorld::with_options(schematic.0.clone(), options)
.map(|w| Box::new(MchprsWorld(w)))
.map_err(|_| NucleationError::Simulation)
}
pub fn simulate_use_block(
schematic: &Schematic,
ticks: u32,
events_xyz: &[i32],
) -> Result<Box<Schematic>, NucleationError> {
let mut world = crate::simulation::MchprsWorld::new(schematic.0.clone())
.map_err(|_| NucleationError::Simulation)?;
for ev in events_xyz.chunks_exact(3) {
world.on_use_block(MPos::new(ev[0], ev[1], ev[2]));
}
world.tick(ticks);
world.sync_to_schematic();
Ok(Box::new(Schematic(world.into_schematic())))
}
pub fn tick(&mut self, ticks: u32) {
self.0.tick(ticks);
}
pub fn flush(&mut self) {
self.0.flush();
}
pub fn set_lever_power(&mut self, x: i32, y: i32, z: i32, powered: bool) {
self.0.set_lever_power(MPos::new(x, y, z), powered);
}
pub fn get_lever_power(&self, x: i32, y: i32, z: i32) -> bool {
self.0.get_lever_power(MPos::new(x, y, z))
}
pub fn is_lit(&self, x: i32, y: i32, z: i32) -> bool {
self.0.is_lit(MPos::new(x, y, z))
}
pub fn set_signal_strength(&mut self, x: i32, y: i32, z: i32, strength: u8) {
self.0.set_signal_strength(MPos::new(x, y, z), strength);
}
pub fn get_signal_strength(&self, x: i32, y: i32, z: i32) -> u8 {
self.0.get_signal_strength(MPos::new(x, y, z))
}
pub fn on_use_block(&mut self, x: i32, y: i32, z: i32) {
self.0.on_use_block(MPos::new(x, y, z));
}
pub fn sync_to_schematic(&mut self) {
self.0.sync_to_schematic();
}
pub fn get_schematic(&self) -> Box<Schematic> {
Box::new(Schematic(self.0.get_schematic().clone()))
}
pub fn get_redstone_power(&self, x: i32, y: i32, z: i32) -> u8 {
self.0.get_redstone_power(MPos::new(x, y, z))
}
pub fn check_custom_io_changes(&mut self) {
self.0.check_custom_io_changes();
}
pub fn poll_custom_io_changes_json(&mut self, out: &mut DiplomatWrite) {
let changes = self.0.poll_custom_io_changes();
let _ = write!(out, "{}", super::serialize_custom_io_changes(&changes));
}
pub fn peek_custom_io_changes_json(&self, out: &mut DiplomatWrite) {
let changes = self.0.peek_custom_io_changes();
let _ = write!(out, "{}", super::serialize_custom_io_changes(changes));
}
pub fn clear_custom_io_changes(&mut self) {
self.0.clear_custom_io_changes();
}
pub fn export_graph(&self) -> Result<Box<RedstoneGraph>, NucleationError> {
self.0
.export_graph()
.map(|g| Box::new(RedstoneGraph(g)))
.map_err(|_| NucleationError::Simulation)
}
pub fn export_graph_structural(&self) -> Result<Box<RedstoneGraph>, NucleationError> {
self.0
.export_graph_structural()
.map(|g| Box::new(RedstoneGraph(g)))
.map_err(|_| NucleationError::Simulation)
}
}
#[diplomat::opaque]
pub struct Value(pub(crate) InnerValue);
impl Value {
pub fn from_u32(v: u32) -> Box<Value> {
Box::new(Value(InnerValue::U32(v)))
}
pub fn from_i32(v: i32) -> Box<Value> {
Box::new(Value(InnerValue::I32(v)))
}
pub fn from_f32(v: f32) -> Box<Value> {
Box::new(Value(InnerValue::F32(v)))
}
pub fn from_bool(v: bool) -> Box<Value> {
Box::new(Value(InnerValue::Bool(v)))
}
pub fn from_string(s: &DiplomatStr) -> Result<Box<Value>, NucleationError> {
let s = std::str::from_utf8(s).map_err(|_| NucleationError::InvalidArgument)?;
Ok(Box::new(Value(InnerValue::String(s.to_string()))))
}
pub fn as_u32(&self) -> Result<u32, NucleationError> {
self.0
.as_u32()
.map_err(|_| NucleationError::InvalidArgument)
}
pub fn as_i32(&self) -> Result<i32, NucleationError> {
self.0
.as_i32()
.map_err(|_| NucleationError::InvalidArgument)
}
pub fn as_f32(&self) -> Result<f32, NucleationError> {
self.0
.as_f32()
.map_err(|_| NucleationError::InvalidArgument)
}
pub fn as_bool(&self) -> Result<bool, NucleationError> {
self.0
.as_bool()
.map_err(|_| NucleationError::InvalidArgument)
}
pub fn as_string(&self, out: &mut DiplomatWrite) -> Result<(), NucleationError> {
let s = self
.0
.as_str()
.map_err(|_| NucleationError::InvalidArgument)?;
let _ = write!(out, "{}", s);
Ok(())
}
pub fn type_name(&self, out: &mut DiplomatWrite) {
let name = match &self.0 {
InnerValue::U32(_) => "u32",
InnerValue::U64(_) => "u64",
InnerValue::I32(_) => "i32",
InnerValue::I64(_) => "i64",
InnerValue::F32(_) => "f32",
InnerValue::Bool(_) => "bool",
InnerValue::String(_) => "string",
InnerValue::BitArray(_) => "bit_array",
InnerValue::Bytes(_) => "bytes",
InnerValue::Array(_) => "array",
InnerValue::Struct(_) => "struct",
};
let _ = write!(out, "{}", name);
}
}
#[diplomat::opaque]
pub struct IoType(pub(crate) InnerIoType);
impl IoType {
pub fn unsigned_int(bits: u32) -> Box<IoType> {
Box::new(IoType(InnerIoType::UnsignedInt {
bits: bits as usize,
}))
}
pub fn signed_int(bits: u32) -> Box<IoType> {
Box::new(IoType(InnerIoType::SignedInt {
bits: bits as usize,
}))
}
pub fn float32() -> Box<IoType> {
Box::new(IoType(InnerIoType::Float32))
}
pub fn boolean() -> Box<IoType> {
Box::new(IoType(InnerIoType::Boolean))
}
pub fn ascii(chars: u32) -> Box<IoType> {
Box::new(IoType(InnerIoType::Ascii {
chars: chars as usize,
}))
}
}
#[diplomat::opaque]
pub struct LayoutFunction(pub(crate) InnerLayoutFunction);
impl LayoutFunction {
pub fn one_to_one() -> Box<LayoutFunction> {
Box::new(LayoutFunction(InnerLayoutFunction::OneToOne))
}
pub fn packed4() -> Box<LayoutFunction> {
Box::new(LayoutFunction(InnerLayoutFunction::Packed4))
}
pub fn custom(mapping: &[u32]) -> Result<Box<LayoutFunction>, NucleationError> {
if mapping.is_empty() {
return Err(NucleationError::InvalidArgument);
}
Ok(Box::new(LayoutFunction(InnerLayoutFunction::Custom(
mapping.iter().map(|&m| m as usize).collect(),
))))
}
pub fn row_major(rows: u32, cols: u32, bits_per_element: u32) -> Box<LayoutFunction> {
Box::new(LayoutFunction(InnerLayoutFunction::RowMajor {
rows: rows as usize,
cols: cols as usize,
bits_per_element: bits_per_element as usize,
}))
}
pub fn column_major(rows: u32, cols: u32, bits_per_element: u32) -> Box<LayoutFunction> {
Box::new(LayoutFunction(InnerLayoutFunction::ColumnMajor {
rows: rows as usize,
cols: cols as usize,
bits_per_element: bits_per_element as usize,
}))
}
pub fn scanline(width: u32, height: u32, bits_per_pixel: u32) -> Box<LayoutFunction> {
Box::new(LayoutFunction(InnerLayoutFunction::Scanline {
width: width as usize,
height: height as usize,
bits_per_pixel: bits_per_pixel as usize,
}))
}
}
#[diplomat::opaque]
pub struct OutputCondition(pub(crate) InnerOutputCondition);
impl OutputCondition {
pub fn equals(value: &Value) -> Box<OutputCondition> {
Box::new(OutputCondition(InnerOutputCondition::Equals(
value.0.clone(),
)))
}
pub fn not_equals(value: &Value) -> Box<OutputCondition> {
Box::new(OutputCondition(InnerOutputCondition::NotEquals(
value.0.clone(),
)))
}
pub fn greater_than(value: &Value) -> Box<OutputCondition> {
Box::new(OutputCondition(InnerOutputCondition::GreaterThan(
value.0.clone(),
)))
}
pub fn less_than(value: &Value) -> Box<OutputCondition> {
Box::new(OutputCondition(InnerOutputCondition::LessThan(
value.0.clone(),
)))
}
pub fn bitwise_and(mask: u32) -> Box<OutputCondition> {
Box::new(OutputCondition(InnerOutputCondition::BitwiseAnd(
mask as u64,
)))
}
}
#[diplomat::opaque]
pub struct ExecutionMode(pub(crate) InnerExecutionMode);
impl ExecutionMode {
pub fn fixed_ticks(ticks: u32) -> Box<ExecutionMode> {
Box::new(ExecutionMode(InnerExecutionMode::FixedTicks { ticks }))
}
pub fn until_condition(
output_name: &DiplomatStr,
condition: &OutputCondition,
max_ticks: u32,
check_interval: u32,
) -> Result<Box<ExecutionMode>, NucleationError> {
let name =
std::str::from_utf8(output_name).map_err(|_| NucleationError::InvalidArgument)?;
Ok(Box::new(ExecutionMode(
InnerExecutionMode::UntilCondition {
output_name: name.to_string(),
condition: condition.0.clone(),
max_ticks,
check_interval,
},
)))
}
pub fn until_change(max_ticks: u32, check_interval: u32) -> Box<ExecutionMode> {
Box::new(ExecutionMode(InnerExecutionMode::UntilChange {
max_ticks,
check_interval,
}))
}
pub fn until_stable(stable_ticks: u32, max_ticks: u32) -> Box<ExecutionMode> {
Box::new(ExecutionMode(InnerExecutionMode::UntilStable {
stable_ticks,
max_ticks,
}))
}
}
#[diplomat::opaque]
pub struct SortStrategy(pub(crate) InnerSortStrategy);
impl SortStrategy {
pub fn yxz() -> Box<SortStrategy> {
Box::new(SortStrategy(InnerSortStrategy::YXZ))
}
pub fn xyz() -> Box<SortStrategy> {
Box::new(SortStrategy(InnerSortStrategy::XYZ))
}
pub fn zyx() -> Box<SortStrategy> {
Box::new(SortStrategy(InnerSortStrategy::ZYX))
}
pub fn y_desc_xz() -> Box<SortStrategy> {
Box::new(SortStrategy(InnerSortStrategy::YDescXZ))
}
pub fn x_desc_yz() -> Box<SortStrategy> {
Box::new(SortStrategy(InnerSortStrategy::XDescYZ))
}
pub fn z_desc_yx() -> Box<SortStrategy> {
Box::new(SortStrategy(InnerSortStrategy::ZDescYX))
}
pub fn descending() -> Box<SortStrategy> {
Box::new(SortStrategy(InnerSortStrategy::YXZDesc))
}
pub fn distance_from(x: i32, y: i32, z: i32) -> Box<SortStrategy> {
Box::new(SortStrategy(InnerSortStrategy::DistanceFrom {
reference: (x, y, z),
}))
}
pub fn distance_from_desc(x: i32, y: i32, z: i32) -> Box<SortStrategy> {
Box::new(SortStrategy(InnerSortStrategy::DistanceFromDesc {
reference: (x, y, z),
}))
}
pub fn preserve() -> Box<SortStrategy> {
Box::new(SortStrategy(InnerSortStrategy::Preserve))
}
pub fn reverse() -> Box<SortStrategy> {
Box::new(SortStrategy(InnerSortStrategy::Reverse))
}
pub fn from_string(s: &DiplomatStr) -> Result<Box<SortStrategy>, NucleationError> {
let s = std::str::from_utf8(s).map_err(|_| NucleationError::InvalidArgument)?;
InnerSortStrategy::from_str(s)
.map(|st| Box::new(SortStrategy(st)))
.ok_or(NucleationError::InvalidArgument)
}
pub fn name(&self, out: &mut DiplomatWrite) {
let _ = write!(out, "{}", self.0.name());
}
}
#[diplomat::opaque_mut]
pub struct IoLayoutBuilder(pub(crate) Option<InnerIoLayoutBuilder>);
impl IoLayoutBuilder {
pub fn create() -> Box<IoLayoutBuilder> {
Box::new(IoLayoutBuilder(Some(InnerIoLayoutBuilder::new())))
}
pub fn add_input(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
layout: &LayoutFunction,
positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
match inner.add_input(
name,
io_type.0.clone(),
layout.0.clone(),
super::positions_from_flat(positions),
) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn add_output(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
layout: &LayoutFunction,
positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
match inner.add_output(
name,
io_type.0.clone(),
layout.0.clone(),
super::positions_from_flat(positions),
) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn add_input_auto(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
match inner.add_input_auto(
name,
io_type.0.clone(),
super::positions_from_flat(positions),
) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn add_output_auto(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
match inner.add_output_auto(
name,
io_type.0.clone(),
super::positions_from_flat(positions),
) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn add_input_from_region(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
layout: &LayoutFunction,
region_positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.add_input_from_region(name, io_type.0.clone(), layout.0.clone(), region) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn add_input_from_region_auto(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
region_positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.add_input_from_region_auto(name, io_type.0.clone(), region) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn add_output_from_region(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
layout: &LayoutFunction,
region_positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.add_output_from_region(name, io_type.0.clone(), layout.0.clone(), region) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn add_output_from_region_auto(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
region_positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.add_output_from_region_auto(name, io_type.0.clone(), region) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn build(&mut self) -> Result<Box<IoLayout>, NucleationError> {
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
Ok(Box::new(IoLayout(inner.build())))
}
}
#[diplomat::opaque]
pub struct IoLayout(pub(crate) InnerIoLayout);
impl IoLayout {
pub fn input_names_json(&self, out: &mut DiplomatWrite) {
let names: Vec<&str> = self.0.input_names();
let json = serde_json::to_string(&names).unwrap_or_else(|_| "[]".to_string());
let _ = write!(out, "{}", json);
}
pub fn output_names_json(&self, out: &mut DiplomatWrite) {
let names: Vec<&str> = self.0.output_names();
let json = serde_json::to_string(&names).unwrap_or_else(|_| "[]".to_string());
let _ = write!(out, "{}", json);
}
}
#[diplomat::opaque_mut]
pub struct CircuitBuilder(pub(crate) Option<InnerCircuitBuilder>);
impl CircuitBuilder {
pub fn create(schematic: &Schematic) -> Box<CircuitBuilder> {
Box::new(CircuitBuilder(Some(InnerCircuitBuilder::new(
schematic.0.clone(),
))))
}
pub fn from_insign(schematic: &Schematic) -> Result<Box<CircuitBuilder>, NucleationError> {
InnerCircuitBuilder::from_insign(schematic.0.clone())
.map(|b| Box::new(CircuitBuilder(Some(b))))
.map_err(|_| NucleationError::Simulation)
}
pub fn with_input(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
layout: &LayoutFunction,
region_positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.with_input(name, io_type.0.clone(), layout.0.clone(), region) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn with_input_sorted(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
layout: &LayoutFunction,
region_positions: &[i32],
sort: &SortStrategy,
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.with_input_sorted(
name,
io_type.0.clone(),
layout.0.clone(),
region,
sort.0.clone(),
) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn with_input_auto(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
region_positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.with_input_auto(name, io_type.0.clone(), region) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn with_input_auto_sorted(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
region_positions: &[i32],
sort: &SortStrategy,
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.with_input_auto_sorted(name, io_type.0.clone(), region, sort.0.clone()) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn with_output(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
layout: &LayoutFunction,
region_positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.with_output(name, io_type.0.clone(), layout.0.clone(), region) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn with_output_sorted(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
layout: &LayoutFunction,
region_positions: &[i32],
sort: &SortStrategy,
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.with_output_sorted(
name,
io_type.0.clone(),
layout.0.clone(),
region,
sort.0.clone(),
) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn with_output_auto(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
region_positions: &[i32],
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.with_output_auto(name, io_type.0.clone(), region) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn with_output_auto_sorted(
&mut self,
name: &DiplomatStr,
io_type: &IoType,
region_positions: &[i32],
sort: &SortStrategy,
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let region =
DefinitionRegion::from_positions(&super::positions_from_flat(region_positions));
match inner.with_output_auto_sorted(name, io_type.0.clone(), region, sort.0.clone()) {
Ok(b) => {
self.0 = Some(b);
Ok(())
}
Err(_) => Err(NucleationError::InvalidArgument),
}
}
pub fn with_options(
&mut self,
optimize: bool,
io_only: bool,
) -> Result<(), NucleationError> {
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
let options = SimulationOptions {
optimize,
io_only,
custom_io: Vec::new(),
};
self.0 = Some(inner.with_options(options));
Ok(())
}
pub fn with_state_mode(&mut self, mode: &DiplomatStr) -> Result<(), NucleationError> {
let mode = std::str::from_utf8(mode).map_err(|_| NucleationError::InvalidArgument)?;
let state_mode =
super::parse_state_mode(mode).ok_or(NucleationError::InvalidArgument)?;
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
self.0 = Some(inner.with_state_mode(state_mode));
Ok(())
}
pub fn validate(&self) -> Result<(), NucleationError> {
match &self.0 {
Some(inner) => inner
.validate()
.map(|_| ())
.map_err(|_| NucleationError::Simulation),
None => Err(NucleationError::AlreadyConsumed),
}
}
pub fn build(&mut self) -> Result<Box<TypedCircuitExecutor>, NucleationError> {
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
inner
.build()
.map(|e| Box::new(TypedCircuitExecutor(e)))
.map_err(|_| NucleationError::Simulation)
}
pub fn build_validated(&mut self) -> Result<Box<TypedCircuitExecutor>, NucleationError> {
let inner = self.0.take().ok_or(NucleationError::AlreadyConsumed)?;
inner
.build_validated()
.map(|e| Box::new(TypedCircuitExecutor(e)))
.map_err(|_| NucleationError::Simulation)
}
pub fn input_count(&self) -> u32 {
match &self.0 {
Some(inner) => inner.input_count() as u32,
None => 0,
}
}
pub fn output_count(&self) -> u32 {
match &self.0 {
Some(inner) => inner.output_count() as u32,
None => 0,
}
}
pub fn input_names_json(&self, out: &mut DiplomatWrite) -> Result<(), NucleationError> {
let inner = self.0.as_ref().ok_or(NucleationError::AlreadyConsumed)?;
let names: Vec<&str> = inner.input_names();
let json = serde_json::to_string(&names).unwrap_or_else(|_| "[]".to_string());
let _ = write!(out, "{}", json);
Ok(())
}
pub fn output_names_json(&self, out: &mut DiplomatWrite) -> Result<(), NucleationError> {
let inner = self.0.as_ref().ok_or(NucleationError::AlreadyConsumed)?;
let names: Vec<&str> = inner.output_names();
let json = serde_json::to_string(&names).unwrap_or_else(|_| "[]".to_string());
let _ = write!(out, "{}", json);
Ok(())
}
}
#[diplomat::opaque_mut]
pub struct TypedCircuitExecutor(pub(crate) InnerTypedCircuitExecutor);
impl TypedCircuitExecutor {
pub fn from_layout(
world: &MchprsWorld,
layout: &IoLayout,
) -> Result<Box<TypedCircuitExecutor>, NucleationError> {
let schematic = world.0.get_schematic().clone();
let new_world = crate::simulation::MchprsWorld::new(schematic)
.map_err(|_| NucleationError::Simulation)?;
Ok(Box::new(TypedCircuitExecutor(
InnerTypedCircuitExecutor::from_layout(new_world, layout.0.clone()),
)))
}
pub fn from_layout_with_options(
world: &MchprsWorld,
layout: &IoLayout,
optimize: bool,
io_only: bool,
) -> Result<Box<TypedCircuitExecutor>, NucleationError> {
let schematic = world.0.get_schematic().clone();
let options = SimulationOptions {
optimize,
io_only,
custom_io: Vec::new(),
};
let new_world =
crate::simulation::MchprsWorld::with_options(schematic, options.clone())
.map_err(|_| NucleationError::Simulation)?;
Ok(Box::new(TypedCircuitExecutor(
InnerTypedCircuitExecutor::from_layout_with_options(
new_world,
layout.0.clone(),
options,
),
)))
}
pub fn from_insign(
schematic: &Schematic,
) -> Result<Box<TypedCircuitExecutor>, NucleationError> {
crate::simulation::circuit_builder::create_circuit_from_insign(&schematic.0)
.map(|e| Box::new(TypedCircuitExecutor(e)))
.map_err(|_| NucleationError::Simulation)
}
pub fn from_insign_with_options(
schematic: &Schematic,
optimize: bool,
io_only: bool,
) -> Result<Box<TypedCircuitExecutor>, NucleationError> {
let options = SimulationOptions {
optimize,
io_only,
custom_io: Vec::new(),
};
crate::simulation::circuit_builder::create_circuit_from_insign_with_options(
&schematic.0,
options,
)
.map(|e| Box::new(TypedCircuitExecutor(e)))
.map_err(|_| NucleationError::Simulation)
}
pub fn set_state_mode(&mut self, mode: &DiplomatStr) -> Result<(), NucleationError> {
let mode = std::str::from_utf8(mode).map_err(|_| NucleationError::InvalidArgument)?;
let state_mode =
super::parse_state_mode(mode).ok_or(NucleationError::InvalidArgument)?;
self.0.set_state_mode(state_mode);
Ok(())
}
pub fn reset(&mut self) -> Result<(), NucleationError> {
self.0.reset().map_err(|_| NucleationError::Simulation)
}
pub fn tick(&mut self, ticks: u32) {
self.0.tick(ticks);
}
pub fn flush(&mut self) {
self.0.flush();
}
pub fn set_input(
&mut self,
name: &DiplomatStr,
value: &Value,
) -> Result<(), NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
self.0
.set_input(name, &value.0)
.map_err(|_| NucleationError::Simulation)
}
pub fn read_output(&mut self, name: &DiplomatStr) -> Result<Box<Value>, NucleationError> {
let name = std::str::from_utf8(name).map_err(|_| NucleationError::InvalidArgument)?;
self.0
.read_output(name)
.map(|v| Box::new(Value(v)))
.map_err(|_| NucleationError::Simulation)
}
pub fn execute(
&mut self,
inputs_json: &DiplomatStr,
mode: &ExecutionMode,
out: &mut DiplomatWrite,
) -> Result<(), NucleationError> {
let json =
std::str::from_utf8(inputs_json).map_err(|_| NucleationError::InvalidArgument)?;
let inputs =
super::parse_inputs_json(json).map_err(|_| NucleationError::InvalidArgument)?;
let result = self
.0
.execute(inputs, mode.0.clone())
.map_err(|_| NucleationError::Simulation)?;
let _ = write!(out, "{}", super::serialize_execution_result(&result));
Ok(())
}
pub fn input_names_json(&self, out: &mut DiplomatWrite) {
let names: Vec<&str> = self.0.input_names();
let json = serde_json::to_string(&names).unwrap_or_else(|_| "[]".to_string());
let _ = write!(out, "{}", json);
}
pub fn output_names_json(&self, out: &mut DiplomatWrite) {
let names: Vec<&str> = self.0.output_names();
let json = serde_json::to_string(&names).unwrap_or_else(|_| "[]".to_string());
let _ = write!(out, "{}", json);
}
pub fn layout_info_json(&self, out: &mut DiplomatWrite) {
let info = self.0.get_layout_info();
let _ = write!(out, "{}", super::serialize_layout_info(&info));
}
pub fn sync_to_schematic(&mut self) -> Box<Schematic> {
Box::new(Schematic(self.0.sync_and_get_schematic().clone()))
}
}
#[diplomat::opaque]
pub struct RedstoneGraph(pub(crate) crate::simulation::graph::RedstoneGraph);
impl RedstoneGraph {
pub fn node_count(&self) -> u32 {
self.0.node_count() as u32
}
pub fn edge_count(&self) -> u32 {
self.0.edge_count() as u32
}
pub fn nodes_json(&self, out: &mut DiplomatWrite) -> Result<(), NucleationError> {
let json = self
.0
.nodes_json()
.map_err(|_| NucleationError::Serialize)?;
let _ = write!(out, "{}", json);
Ok(())
}
pub fn edges_json(&self, out: &mut DiplomatWrite) -> Result<(), NucleationError> {
let json = self
.0
.edges_json()
.map_err(|_| NucleationError::Serialize)?;
let _ = write!(out, "{}", json);
Ok(())
}
pub fn features_json(&self, out: &mut DiplomatWrite) -> Result<(), NucleationError> {
let json = self
.0
.features()
.to_json()
.map_err(|_| NucleationError::Serialize)?;
let _ = write!(out, "{}", json);
Ok(())
}
pub fn fingerprint(
&self,
preset: &DiplomatStr,
out: &mut DiplomatWrite,
) -> Result<(), NucleationError> {
let preset =
std::str::from_utf8(preset).map_err(|_| NucleationError::InvalidArgument)?;
let preset = if preset.is_empty() {
"structural"
} else {
preset
};
let spec = crate::simulation::fingerprint::GraphFingerprintSpec::from_preset(preset)
.ok_or(NucleationError::InvalidArgument)?;
let _ = write!(out, "{}", self.0.fingerprint(&spec).to_hex());
Ok(())
}
pub fn to_json(&self, out: &mut DiplomatWrite) -> Result<(), NucleationError> {
let json = self.0.to_json().map_err(|_| NucleationError::Serialize)?;
let _ = write!(out, "{}", json);
Ok(())
}
pub fn from_json(json: &DiplomatStr) -> Result<Box<RedstoneGraph>, NucleationError> {
let json = std::str::from_utf8(json).map_err(|_| NucleationError::InvalidArgument)?;
crate::simulation::graph::RedstoneGraph::from_json(json)
.map(|g| Box::new(RedstoneGraph(g)))
.map_err(|_| NucleationError::Parse)
}
}
}