1#![allow(dead_code)]
3
4use serde::de::DeserializeOwned;
5use serde::{Deserialize, Serialize};
6
7use crate::context::Context;
8use crate::error::IxaError;
9
10pub(crate) trait ExtApi {
11 type Args: DeserializeOwned;
12 type Retval: Serialize;
13
14 fn run(context: &mut Context, args: &Self::Args) -> Result<Self::Retval, IxaError>;
15}
16
17#[derive(Serialize, Deserialize, Debug)]
18pub(crate) struct EmptyArgs {}
19
20pub(crate) fn run_ext_api<T: ExtApi>(
21 context: &mut Context,
22 args: &T::Args,
23) -> Result<T::Retval, IxaError> {
24 T::run(context, args)
25}
26
27pub(crate) mod global_properties {
28 use clap::{Parser, Subcommand};
29 use serde::{Deserialize, Serialize};
30
31 use crate::context::Context;
32 use crate::global_properties::ContextGlobalPropertiesExt;
33 use crate::IxaError;
34
35 pub(crate) struct Api {}
36 #[derive(Serialize, Deserialize, Debug)]
37 pub(crate) enum Retval {
38 List(Vec<String>),
39 Value(String),
40 }
41 #[derive(Subcommand, Clone, Debug, Serialize, Deserialize)]
42 pub(crate) enum ArgsEnum {
44 List,
46
47 Get {
49 property: String,
51 },
52 }
53
54 #[derive(Parser, Debug, Serialize, Deserialize)]
55 pub(crate) enum Args {
56 #[command(subcommand)]
57 Global(ArgsEnum),
58 }
59 impl super::ExtApi for Api {
60 type Args = Args;
61 type Retval = Retval;
62
63 fn run(context: &mut Context, args: &Args) -> Result<Retval, IxaError> {
64 let Args::Global(global_args) = args;
65
66 match global_args {
67 ArgsEnum::List => Ok(Retval::List(context.list_registered_global_properties())),
68 ArgsEnum::Get { property: name } => {
69 let output = context.get_serialized_value_by_string(name)?;
70 match output {
71 Some(value) => Ok(Retval::Value(value)),
72 None => Err(IxaError::PropertyNotSet { name: name.clone() }),
73 }
74 }
75 }
76 }
77 }
78}
79
80pub(crate) mod breakpoint {
81 use clap::{Parser, Subcommand};
82 use serde::{Deserialize, Serialize};
83
84 use crate::context::Context;
85 use crate::debugger::enter_debugger;
86 use crate::{trace, IxaError};
87
88 #[derive(Subcommand, Clone, Debug, Serialize, Deserialize)]
89 pub(crate) enum ArgsEnum {
91 List,
93 Set {
95 #[arg(required = true)]
96 time: f64,
97 #[arg(long, hide = true, default_value_t = true)]
98 console: bool,
99 },
100 #[group(multiple = false, required = true)]
103 Delete {
104 #[arg(value_name = "ID")]
106 id: Option<u32>,
107
108 #[arg(long, action)]
110 all: bool,
111 },
112 Disable,
114 Enable,
116 }
117
118 #[derive(Parser, Debug, Serialize, Deserialize)]
119 pub(crate) enum Args {
120 #[command(subcommand)]
121 Breakpoint(ArgsEnum),
122 }
123
124 #[derive(Serialize, Deserialize, Debug)]
125 pub(crate) enum Retval {
126 List(Vec<String>),
127 Ok,
128 }
129
130 pub(crate) struct Api {}
131 impl super::ExtApi for Api {
132 type Args = Args;
133 type Retval = Retval;
134
135 fn run(context: &mut Context, args: &Args) -> Result<Retval, IxaError> {
136 let Args::Breakpoint(breakpoint_args) = args;
137
138 match breakpoint_args {
139 ArgsEnum::List => {
140 trace!("Listing breakpoints");
141 let list = context.list_breakpoints(0);
142 let list = list
143 .iter()
144 .map(|schedule| {
145 format!(
146 "{}: t={} ({})",
147 schedule.plan_id, schedule.time, schedule.priority
148 )
149 })
150 .collect::<Vec<String>>();
151 Ok(Retval::List(list))
152 }
153
154 #[allow(unused_variables)]
155 ArgsEnum::Set { time, console } => {
156 if *time < context.get_current_time() {
157 return Err(IxaError::BreakpointTimeInPast { time: *time });
158 }
159 context.schedule_debugger(*time, None, Box::new(enter_debugger));
160
161 trace!("Breakpoint set at t={time}");
162 Ok(Retval::Ok)
163 }
164
165 ArgsEnum::Delete { id, all } => {
166 if let Some(id) = id {
167 assert!(!all);
168 trace!("Deleting breakpoint {id}");
169 let cancelled = context.delete_breakpoint(u64::from(*id));
170 if cancelled.is_none() {
171 Err(IxaError::BreakpointNotFound { id: *id })
172 } else {
173 Ok(Retval::Ok)
174 }
175 } else {
176 assert!(all);
177 trace!("Deleting all breakpoints");
178 context.clear_breakpoints();
179 Ok(Retval::Ok)
180 }
181 }
182
183 ArgsEnum::Disable => {
184 trace!("Disabling all breakpoints");
185 context.disable_breakpoints();
186 Ok(Retval::Ok)
187 }
188
189 ArgsEnum::Enable => {
190 trace!("Enabling all breakpoints");
191 context.enable_breakpoints();
192 Ok(Retval::Ok)
193 }
194 }
195 }
196 }
197}
198
199pub(crate) mod next {
200 use clap::Parser;
201 use serde::Serialize;
202 use serde_derive::Deserialize;
203
204 use crate::context::Context;
205 use crate::external_api::EmptyArgs;
206 use crate::IxaError;
207
208 #[derive(Parser, Debug, Serialize, Deserialize)]
209 pub enum Args {
210 Next,
212 }
213
214 #[derive(Serialize)]
215 pub(crate) enum Retval {
216 Ok,
217 }
218 #[allow(unused)]
219 pub(crate) struct Api {}
220 impl super::ExtApi for Api {
221 type Args = EmptyArgs;
222 type Retval = Retval;
223
224 fn run(_context: &mut Context, _args: &EmptyArgs) -> Result<Retval, IxaError> {
225 Ok(Retval::Ok)
227 }
228 }
229}
230
231pub(crate) mod halt {
232 use clap::Parser;
233 use serde::Serialize;
234 use serde_derive::Deserialize;
235
236 use crate::context::Context;
237 use crate::external_api::EmptyArgs;
238 use crate::IxaError;
239
240 #[derive(Parser, Debug, Serialize, Deserialize)]
241 pub enum Args {
242 Halt,
244 }
245
246 #[derive(Serialize)]
247 pub(crate) enum Retval {
248 Ok,
249 }
250 #[allow(unused)]
251 pub(crate) struct Api {}
252 impl super::ExtApi for Api {
253 type Args = EmptyArgs;
254 type Retval = Retval;
255
256 fn run(_context: &mut Context, _args: &EmptyArgs) -> Result<Retval, IxaError> {
257 Ok(Retval::Ok)
259 }
260 }
261}
262
263pub(crate) mod r#continue {
264 use clap::Parser;
265 use serde_derive::{Deserialize, Serialize};
266
267 use crate::context::Context;
268 use crate::external_api::EmptyArgs;
269 use crate::IxaError;
270
271 #[derive(Parser, Debug, Serialize, Deserialize)]
272 pub enum Args {
273 Continue,
275 }
276
277 #[derive(Serialize)]
278 pub(crate) enum Retval {
279 Ok,
280 }
281 #[allow(unused)]
282 pub(crate) struct Api {}
283 impl super::ExtApi for Api {
284 type Args = EmptyArgs;
285 type Retval = Retval;
286
287 fn run(_context: &mut Context, _args: &EmptyArgs) -> Result<Retval, IxaError> {
288 Ok(Retval::Ok)
290 }
291 }
292}
293
294pub(crate) mod time {
295 #![allow(clippy::float_cmp)]
296 use clap::Parser;
297 use serde::{Deserialize, Serialize};
298
299 use crate::context::Context;
300 use crate::external_api::EmptyArgs;
301 use crate::IxaError;
302
303 pub(crate) struct Api {}
304 #[derive(Parser, Debug, Deserialize)]
305 pub(crate) enum Args {
306 Time,
308 }
309
310 #[derive(Serialize)]
311 pub(crate) struct Retval {
312 pub time: f64,
313 }
314 impl super::ExtApi for Api {
315 type Args = super::EmptyArgs;
316 type Retval = Retval;
317
318 fn run(context: &mut Context, _args: &EmptyArgs) -> Result<Retval, IxaError> {
319 Ok(Retval {
320 time: context.get_current_time(),
321 })
322 }
323 }
324
325 #[cfg(test)]
326 mod test {
327 use crate::Context;
328
329 #[test]
330 fn test() {
331 let mut context = Context::new();
332
333 let result = crate::external_api::run_ext_api::<super::Api>(
334 &mut context,
335 &crate::external_api::EmptyArgs {},
336 );
337
338 assert_eq!(result.unwrap().time, 0.0);
339 }
340 }
341}