Skip to content

Commit 9d75c6f

Browse files
committed
feat: added core types
1 parent 9bc9478 commit 9d75c6f

14 files changed

Lines changed: 1255 additions & 0 deletions

File tree

crates/taurus-core/src/runtime/engine.rs

Lines changed: 483 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//! Runtime execution surfaces.
2+
//!
3+
//! `engine` is the public execution API. The remaining modules contain runtime
4+
//! internals and transport-specific abstractions used by the engine.
5+
6+
pub mod engine;
7+
pub mod execution;
8+
pub mod functions;
9+
pub mod remote;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//! Remote runtime execution interface.
2+
//!
3+
//! Local runtime nodes can delegate execution to remote services through this
4+
//! trait without coupling the core engine to a specific transport.
5+
6+
use async_trait::async_trait;
7+
use tucana::{aquila::ExecutionRequest, shared::Value};
8+
9+
use crate::types::errors::runtime_error::RuntimeError;
10+
11+
pub struct RemoteExecution {
12+
/// Remote service identifier to route the call.
13+
pub target_service: String,
14+
/// Execution request payload expected by the remote runtime.
15+
pub request: ExecutionRequest,
16+
}
17+
18+
#[async_trait]
19+
pub trait RemoteRuntime {
20+
/// Execute a remote node invocation and return its resulting value.
21+
async fn execute_remote(&self, execution: RemoteExecution) -> Result<Value, RuntimeError>;
22+
}
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
//! General (application-level) errors that can occur outside pure node execution.
2+
//!
3+
//! Every variant can be converted into a [`RuntimeError`] to unify reporting.
4+
5+
use std::collections::HashMap;
6+
use std::error::Error as StdError;
7+
use std::fmt::{Display, Formatter};
8+
9+
use tucana::shared::Value;
10+
use tucana::shared::value::Kind::StringValue;
11+
12+
use crate::types::errors::runtime_error::RuntimeError;
13+
14+
/// Application-layer failures that should still be reportable as runtime failures.
15+
#[derive(Debug, Clone)]
16+
pub enum Error {
17+
/// Invalid or missing runtime configuration.
18+
Configuration {
19+
message: String,
20+
details: HashMap<String, Value>,
21+
},
22+
/// Invalid application state transition.
23+
State {
24+
message: String,
25+
details: HashMap<String, Value>,
26+
},
27+
/// Failed communication with dependency or transport layer.
28+
Transport {
29+
dependency: String,
30+
message: String,
31+
details: HashMap<String, Value>,
32+
},
33+
/// Failed serialization/deserialization.
34+
Serialization {
35+
format: String,
36+
message: String,
37+
details: HashMap<String, Value>,
38+
},
39+
/// Catch-all internal application error.
40+
Internal {
41+
message: String,
42+
details: HashMap<String, Value>,
43+
},
44+
}
45+
46+
impl Error {
47+
/// Build a configuration error with optional structured details.
48+
pub fn configuration(message: impl Into<String>) -> Self {
49+
Self::Configuration {
50+
message: message.into(),
51+
details: HashMap::new(),
52+
}
53+
}
54+
55+
/// Build an invalid state error with optional structured details.
56+
pub fn state(message: impl Into<String>) -> Self {
57+
Self::State {
58+
message: message.into(),
59+
details: HashMap::new(),
60+
}
61+
}
62+
63+
/// Build a transport/dependency error with optional structured details.
64+
pub fn transport(dependency: impl Into<String>, message: impl Into<String>) -> Self {
65+
Self::Transport {
66+
dependency: dependency.into(),
67+
message: message.into(),
68+
details: HashMap::new(),
69+
}
70+
}
71+
72+
/// Build a serialization error with optional structured details.
73+
pub fn serialization(format: impl Into<String>, message: impl Into<String>) -> Self {
74+
Self::Serialization {
75+
format: format.into(),
76+
message: message.into(),
77+
details: HashMap::new(),
78+
}
79+
}
80+
81+
/// Build an internal application error with optional structured details.
82+
pub fn internal(message: impl Into<String>) -> Self {
83+
Self::Internal {
84+
message: message.into(),
85+
details: HashMap::new(),
86+
}
87+
}
88+
89+
/// Attach a detail entry to this error.
90+
pub fn with_detail(mut self, key: impl Into<String>, value: Value) -> Self {
91+
match &mut self {
92+
Error::Configuration { details, .. }
93+
| Error::State { details, .. }
94+
| Error::Transport { details, .. }
95+
| Error::Serialization { details, .. }
96+
| Error::Internal { details, .. } => {
97+
details.insert(key.into(), value);
98+
}
99+
}
100+
self
101+
}
102+
}
103+
104+
impl From<Error> for RuntimeError {
105+
fn from(value: Error) -> Self {
106+
match value {
107+
Error::Configuration { message, details } => {
108+
let mut err = RuntimeError::with_code(
109+
"T-APP-000001".to_string(),
110+
"Configuration".to_string(),
111+
message,
112+
);
113+
err.details.extend(details);
114+
err
115+
}
116+
Error::State { message, details } => {
117+
let mut err = RuntimeError::with_code(
118+
"T-APP-000002".to_string(),
119+
"State".to_string(),
120+
message,
121+
);
122+
err.details.extend(details);
123+
err
124+
}
125+
Error::Transport {
126+
dependency,
127+
message,
128+
details,
129+
} => {
130+
let mut err = RuntimeError::with_code(
131+
"T-APP-000003".to_string(),
132+
"Transport".to_string(),
133+
message,
134+
)
135+
.with_detail(
136+
"dependency".to_string(),
137+
Value {
138+
kind: Some(StringValue(dependency)),
139+
},
140+
);
141+
err.details.extend(details);
142+
err
143+
}
144+
Error::Serialization {
145+
format,
146+
message,
147+
details,
148+
} => {
149+
let mut err = RuntimeError::with_code(
150+
"T-APP-000004".to_string(),
151+
"Serialization".to_string(),
152+
message,
153+
)
154+
.with_detail(
155+
"format".to_string(),
156+
Value {
157+
kind: Some(StringValue(format)),
158+
},
159+
);
160+
err.details.extend(details);
161+
err
162+
}
163+
Error::Internal { message, details } => {
164+
let mut err = RuntimeError::with_code(
165+
"T-APP-999999".to_string(),
166+
"Internal".to_string(),
167+
message,
168+
);
169+
err.details.extend(details);
170+
err
171+
}
172+
}
173+
}
174+
}
175+
176+
impl StdError for Error {}
177+
178+
impl Display for Error {
179+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
180+
match self {
181+
Error::Configuration { message, .. } => write!(f, "Configuration error: {message}"),
182+
Error::State { message, .. } => write!(f, "State error: {message}"),
183+
Error::Transport {
184+
dependency,
185+
message,
186+
..
187+
} => write!(f, "Transport error ({dependency}): {message}"),
188+
Error::Serialization {
189+
format, message, ..
190+
} => write!(f, "Serialization error ({format}): {message}"),
191+
Error::Internal { message, .. } => write!(f, "Internal error: {message}"),
192+
}
193+
}
194+
}
195+
196+
#[cfg(test)]
197+
mod tests {
198+
use super::*;
199+
use tucana::shared::{Struct, value::Kind::StructValue};
200+
201+
#[test]
202+
fn app_error_converts_to_runtime_error_with_expected_code_and_category() {
203+
let app_err = Error::transport("nats", "connection lost").with_detail(
204+
"subject",
205+
Value {
206+
kind: Some(StringValue("execution.*".to_string())),
207+
},
208+
);
209+
210+
let runtime_error: RuntimeError = app_err.into();
211+
212+
assert_eq!(runtime_error.code, "T-APP-000003");
213+
assert_eq!(runtime_error.category, "Transport");
214+
assert_eq!(runtime_error.message, "connection lost");
215+
assert!(runtime_error.details.contains_key("dependency"));
216+
assert!(runtime_error.details.contains_key("subject"));
217+
}
218+
219+
#[test]
220+
fn runtime_error_value_contains_required_struct_fields() {
221+
let runtime_error: RuntimeError = Error::internal("boom").into();
222+
let value = runtime_error.as_value();
223+
224+
let Some(StructValue(Struct { fields })) = value.kind else {
225+
panic!("expected struct value");
226+
};
227+
228+
assert!(fields.contains_key("code"));
229+
assert!(fields.contains_key("category"));
230+
assert!(fields.contains_key("message"));
231+
assert!(fields.contains_key("timestamp"));
232+
assert!(fields.contains_key("version"));
233+
assert!(fields.contains_key("dependencies"));
234+
assert!(fields.contains_key("details"));
235+
}
236+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//! Error types shared across Taurus runtime execution and application layers.
2+
3+
pub mod error;
4+
pub mod runtime_error;

0 commit comments

Comments
 (0)