reasoninglayer 0.1.2

Rust client SDK for the Reasoning Layer API
Documentation
//! Constraint solving DTOs.

use std::collections::BTreeMap;

use serde::{Deserialize, Serialize};

use super::visualization::VisualizationGraphDto;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RelOpDto {
    Equal,
    NotEqual,
    LessThan,
    LessThanOrEqual,
    GreaterThan,
    GreaterThanOrEqual,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ArithOpDto {
    Add,
    Subtract,
    Multiply,
    Divide,
}

/// Recursive arithmetic expression. Tagged by `type`.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ArithmeticExprDto {
    Constant {
        value: f64,
    },
    Variable {
        name: String,
    },
    BinaryOp {
        op: ArithOpDto,
        left: Box<ArithmeticExprDto>,
        right: Box<ArithmeticExprDto>,
    },
}

/// Arithmetic constraint — tagged by `constraint_type`.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "constraint_type", rename_all = "snake_case")]
pub enum ArithmeticConstraintDto {
    Relation {
        left: ArithmeticExprDto,
        op: RelOpDto,
        right: ArithmeticExprDto,
    },
    Domain {
        variable: String,
        domain: Vec<f64>,
    },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SolveConstraintRequest {
    pub constraints: Vec<ArithmeticConstraintDto>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub initial_bindings: Option<BTreeMap<String, f64>>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct SolveConstraintResponse {
    pub success: bool,
    #[serde(default)]
    pub bindings: BTreeMap<String, f64>,
    #[serde(default)]
    pub suspended_constraints: Vec<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
}

// ─── Constraint graph visualization ───────────────────────────────────────────

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ConstraintGraphRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub term_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub detect_cycles: Option<bool>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub generate_dot: Option<bool>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub include_fd_domains: Option<bool>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ConstraintGraphStats {
    pub total_constraints: u64,
    pub active_constraints: u64,
    pub determined_variables: u64,
    pub cycle_count: u64,
    pub total_variables: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CycleDto {
    #[serde(default)]
    pub nodes: Vec<String>,
    #[serde(default)]
    pub edges: Vec<String>,
    pub is_problematic: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FdDomainStateDto {
    pub variable_id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub variable_name: Option<String>,
    pub is_determined: bool,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub values: Vec<f64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub min: Option<f64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max: Option<f64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConstraintGraphResponse {
    pub graph: VisualizationGraphDto,
    pub stats: ConstraintGraphStats,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub cycles: Option<Vec<CycleDto>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub fd_domains: Option<Vec<FdDomainStateDto>>,
}

// ─── Sessions ─────────────────────────────────────────────────────────────────

/// General constraint (recursive) — tagged by `type`.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum GeneralConstraintDto {
    Arithmetic {
        #[serde(flatten)]
        constraint: ArithmeticConstraintDto,
    },
    Basic {
        constraint_type: String,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        value: Option<serde_json::Value>,
    },
    Conjunction {
        constraints: Vec<GeneralConstraintDto>,
    },
    Disjunction {
        constraints: Vec<GeneralConstraintDto>,
    },
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CreateConstraintSessionRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub metadata: Option<BTreeMap<String, String>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateConstraintSessionResponse {
    pub created_at: u64,
    pub session_id: String,
    pub status: String,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ConstraintSessionStatus {
    pub session_id: String,
    pub created_at: String,
    pub last_accessed: String,
    pub constraint_count: u64,
    pub satisfied_count: u64,
    pub suspended_count: u64,
    #[serde(default)]
    pub current_bindings: BTreeMap<String, f64>,
    pub all_satisfied: bool,
    #[serde(default)]
    pub metadata: BTreeMap<String, String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AddConstraintsRequest {
    pub constraints: Vec<GeneralConstraintDto>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub bindings: Option<BTreeMap<String, serde_json::Value>>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AddConstraintsResponse {
    pub added_count: u64,
    #[serde(default)]
    pub current_bindings: BTreeMap<String, f64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
    pub satisfied_count: u64,
    pub success: bool,
    pub suspended_count: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CleanupSessionsResponse {
    pub message: String,
    pub removed: u64,
    pub success: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BindVariablesRequest {
    pub bindings: BTreeMap<String, f64>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct BindVariablesResponse {
    pub all_satisfied: bool,
    #[serde(default)]
    pub current_bindings: BTreeMap<String, f64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
    pub newly_satisfied: u64,
    pub satisfied_count: u64,
    pub session_id: String,
    pub success: bool,
    pub suspended_count: u64,
}