use serde::{Deserialize, Serialize};
use crate::feature_pipeline::Env;
pub(crate) mod exports;
pub(crate) mod infer;
pub(crate) mod lifecycle;
pub(crate) mod mapping;
pub(crate) mod constraints;
pub use exports::{
assembly_add_constraint_json, assembly_apply_document_json,
assembly_apply_inferred_constraints_json, assembly_dof_json,
assembly_infer_constraints_json, assembly_inferable_types_json,
assembly_move_constraint_json, assembly_overlay_json, assembly_pose_updates_json,
assembly_remove_constraint_json, assembly_run_solve_json,
assembly_set_constraint_enabled_json, assembly_set_constraint_open_json,
assembly_state_json, assembly_statuses_json, assembly_update_constraint_json,
};
pub use constraints::{
constraint_schema_catalogue, constraint_type, ConstraintTypeDef, CONSTRAINT_TYPES,
};
pub use mapping::transform_to_pose_params;
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct AssemblyState {
#[serde(default)]
pub constraints: Vec<ConstraintEntry>,
#[serde(default, rename = "idCounter")]
pub id_counter: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConstraintEntry {
#[serde(rename = "type")]
pub constraint_type: String,
#[serde(rename = "inputParams", default = "empty_object")]
pub input_params: serde_json::Value,
#[serde(rename = "persistentData", default = "empty_object")]
pub persistent_data: serde_json::Value,
#[serde(default = "default_true")]
pub enabled: bool,
#[serde(default)]
pub open: bool,
}
fn empty_object() -> serde_json::Value {
serde_json::Value::Object(serde_json::Map::new())
}
fn default_true() -> bool {
true
}
impl ConstraintEntry {
pub fn id(&self) -> &str {
self.input_params
.get("id")
.and_then(|value| value.as_str())
.unwrap_or("")
}
pub fn elements(&self) -> Vec<String> {
self.input_params
.get("elements")
.and_then(|value| value.as_array())
.map(|items| {
items
.iter()
.filter_map(|item| item.as_str())
.map(str::to_string)
.collect()
})
.unwrap_or_default()
}
pub fn flag(&self, key: &str) -> bool {
self.input_params
.get(key)
.and_then(|value| value.as_bool())
.unwrap_or(false)
}
pub fn number(&self, key: &str, env: &Env, default: f64) -> Result<f64, String> {
match self.input_params.get(key) {
None | Some(serde_json::Value::Null) => Ok(default),
Some(serde_json::Value::Number(number)) => number
.as_f64()
.ok_or_else(|| format!("param `{key}` is not a finite number")),
Some(serde_json::Value::String(source)) => env
.eval(source)
.map_err(|error| format!("param `{key}`: {error}")),
Some(other) => Err(format!(
"param `{key}` must be a number or expression string, found {other}"
)),
}
}
pub fn set_persistent(&mut self, key: &str, value: serde_json::Value) {
if !self.persistent_data.is_object() {
self.persistent_data = empty_object();
}
if let Some(map) = self.persistent_data.as_object_mut() {
map.insert(key.to_string(), value);
}
}
pub fn remove_persistent(&mut self, key: &str) {
if let Some(map) = self.persistent_data.as_object_mut() {
map.remove(key);
}
}
pub fn persistent(&self, key: &str) -> Option<&serde_json::Value> {
self.persistent_data.get(key)
}
pub fn set_status(&mut self, status: &str, message: impl Into<String>, satisfied: bool) {
self.set_persistent("status", serde_json::Value::String(status.to_string()));
self.set_persistent("message", serde_json::Value::String(message.into()));
self.set_persistent("satisfied", serde_json::Value::Bool(satisfied));
if status != "duplicate" {
self.remove_persistent("duplicateConstraintIDs");
self.remove_persistent("duplicateSignature");
}
if status != "satisfied" && status != "adjusted" {
self.remove_persistent("error");
self.remove_persistent("kernel");
}
}
pub fn status(&self) -> &str {
self.persistent("status")
.and_then(|value| value.as_str())
.unwrap_or("")
}
}
pub(crate) fn finish_history_run(
request: &crate::feature_pipeline::HistoryRequest,
scene: &mut crate::feature_pipeline::SceneMap,
env: &Env,
) {
let mut state = request.assembly.clone().unwrap_or_default();
let outcome = if state.constraints.is_empty() {
lifecycle::LifecycleOutcome::empty()
} else {
lifecycle::run_constraints(&mut state, scene, env)
};
exports::install_session(
state,
scene.clone(),
request.expressions.clone(),
request.configurator.clone(),
outcome,
);
}