Skip to main content

sciforge_hub/api/dto/
response.rs

1//! Outbound computation response payload.
2//!
3//! [`ComputeResponse`] wraps the computation result (or error) together
4//! with timing metadata returned to the caller.
5
6/// Outbound computation response.
7#[derive(Debug, Clone)]
8pub struct ComputeResponse {
9    /// Whether the computation succeeded.
10    pub success: bool,
11    /// Computation result, if successful.
12    pub result: Option<ResultData>,
13    /// Error message, if the computation failed.
14    pub error: Option<String>,
15    /// Wall-clock time in milliseconds.
16    pub elapsed_ms: f64,
17}
18
19/// Typed result payload.
20#[derive(Debug, Clone)]
21pub enum ResultData {
22    Scalar(f64),
23    Pair(f64, f64),
24    Triple(f64, f64, f64),
25    Vector(Vec<f64>),
26    Matrix(Vec<Vec<f64>>),
27    TimeSeries {
28        times: Vec<f64>,
29        values: Vec<Vec<f64>>,
30    },
31    Text(String),
32    Boolean(bool),
33}
34
35impl ComputeResponse {
36    /// Builds a successful scalar response.
37    pub fn ok_scalar(value: f64, elapsed_ms: f64) -> Self {
38        Self {
39            success: true,
40            result: Some(ResultData::Scalar(value)),
41            error: None,
42            elapsed_ms,
43        }
44    }
45
46    /// Builds a successful vector response.
47    pub fn ok_vector(values: Vec<f64>, elapsed_ms: f64) -> Self {
48        Self {
49            success: true,
50            result: Some(ResultData::Vector(values)),
51            error: None,
52            elapsed_ms,
53        }
54    }
55
56    /// Builds a successful time-series response.
57    pub fn ok_time_series(times: Vec<f64>, values: Vec<Vec<f64>>, elapsed_ms: f64) -> Self {
58        Self {
59            success: true,
60            result: Some(ResultData::TimeSeries { times, values }),
61            error: None,
62            elapsed_ms,
63        }
64    }
65
66    /// Builds a successful text response.
67    pub fn ok_text(text: String, elapsed_ms: f64) -> Self {
68        Self {
69            success: true,
70            result: Some(ResultData::Text(text)),
71            error: None,
72            elapsed_ms,
73        }
74    }
75
76    /// Builds a failure response with the given error message.
77    pub fn fail(msg: &str, elapsed_ms: f64) -> Self {
78        Self {
79            success: false,
80            result: None,
81            error: Some(msg.to_string()),
82            elapsed_ms,
83        }
84    }
85
86    /// Serializes the response to a JSON string.
87    pub fn to_json(&self) -> String {
88        let result_str = match &self.result {
89            Some(ResultData::Scalar(v)) => format!(r#""result":{v}"#),
90            Some(ResultData::Pair(a, b)) => format!(r#""result":[{a},{b}]"#),
91            Some(ResultData::Triple(a, b, c)) => format!(r#""result":[{a},{b},{c}]"#),
92            Some(ResultData::Vector(v)) => format!(r#""result":{v:?}"#),
93            Some(ResultData::Text(t)) => format!(r#""result":"{t}""#),
94            Some(ResultData::Boolean(b)) => format!(r#""result":{b}"#),
95            Some(ResultData::Matrix(_)) => r#""result":"<matrix>""#.to_string(),
96            Some(ResultData::TimeSeries { .. }) => r#""result":"<time_series>""#.to_string(),
97            None => r#""result":null"#.to_string(),
98        };
99        let err_str = match &self.error {
100            Some(e) => format!(r#""error":"{e}""#),
101            None => r#""error":null"#.to_string(),
102        };
103        format!(
104            r#"{{"success":{},{result_str},{err_str},"elapsed_ms":{}}}"#,
105            self.success, self.elapsed_ms
106        )
107    }
108}