runmat_runtime/context/
runtime.rs1use super::{ContextFuture, RuntimeContextGuard, RuntimeContextState, RuntimeServicePorts};
2use crate::execution::RuntimeExecutionServices;
3use std::future::Future;
4use std::rc::Rc;
5use std::sync::{atomic::AtomicBool, Arc};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum RuntimeLanguageMode {
9 Matlab,
10 RunMat,
11 Strict,
12}
13
14pub const DEFAULT_CALLSTACK_LIMIT: usize = 200;
15pub const DEFAULT_ERROR_NAMESPACE: &str = "RunMat";
16
17#[derive(Clone)]
19pub struct RuntimeContext {
20 execution: Rc<dyn RuntimeExecutionServices>,
21 program_revision: Option<runmat_execution::ProgramRevision>,
22 search_path: Option<Arc<crate::builtins::common::path_state::SearchPath>>,
23 services: RuntimeServicePorts,
24 state: Rc<RuntimeContextState>,
25}
26
27impl std::fmt::Debug for RuntimeContext {
28 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 formatter
30 .debug_struct("RuntimeContext")
31 .field("scope_id", &self.execution.scope_id())
32 .field("program_revision", &self.program_revision)
33 .field("services", &self.services)
34 .finish_non_exhaustive()
35 }
36}
37
38impl RuntimeContext {
39 pub fn new(execution: Rc<dyn RuntimeExecutionServices>) -> Self {
40 Self::with_cancellation(execution, Arc::new(AtomicBool::new(false)))
41 }
42
43 pub fn with_cancellation(
44 execution: Rc<dyn RuntimeExecutionServices>,
45 cancellation: Arc<AtomicBool>,
46 ) -> Self {
47 let state = Rc::new(RuntimeContextState::new(cancellation));
48 crate::class_registry::register_context_state(&state);
49 Self {
50 execution,
51 program_revision: None,
52 search_path: None,
53 services: RuntimeServicePorts::default(),
54 state,
55 }
56 }
57
58 pub fn execution(&self) -> &Rc<dyn RuntimeExecutionServices> {
59 &self.execution
60 }
61
62 pub fn service_ports(&self) -> &RuntimeServicePorts {
63 &self.services
64 }
65
66 pub(crate) fn state(&self) -> &Rc<RuntimeContextState> {
67 &self.state
68 }
69
70 pub(super) fn state_identity(&self) -> *const RuntimeContextState {
71 Rc::as_ptr(&self.state)
72 }
73
74 pub fn cancellation(&self) -> Arc<AtomicBool> {
75 Arc::clone(&self.state.cancellation.borrow())
76 }
77
78 pub fn program_revision(&self) -> Option<&runmat_execution::ProgramRevision> {
79 self.program_revision.as_ref()
80 }
81
82 pub fn with_program_revision(
83 mut self,
84 revision: Option<runmat_execution::ProgramRevision>,
85 ) -> Self {
86 if self.program_revision != revision {
87 if let (Some(service), Some(previous)) =
88 (self.services.placement(), self.program_revision.clone())
89 {
90 service.invalidate(runmat_execution::PlacementInvalidation::Program {
91 revision: previous,
92 });
93 }
94 }
95 self.program_revision = revision;
96 self
97 }
98
99 pub fn with_execution(mut self, execution: Rc<dyn RuntimeExecutionServices>) -> Self {
100 self.execution = execution;
101 self
102 }
103
104 pub fn with_search_path(
105 mut self,
106 search_path: Arc<crate::builtins::common::path_state::SearchPath>,
107 ) -> Self {
108 self.search_path = Some(search_path);
109 self
110 }
111
112 pub fn search_path(&self) -> Option<&Arc<crate::builtins::common::path_state::SearchPath>> {
113 self.search_path.as_ref()
114 }
115
116 pub fn set_dynamic_function_loader(
117 &self,
118 loader: Option<Arc<crate::user_functions::DynamicFunctionLoader>>,
119 ) {
120 self.state.call.borrow_mut().dynamic_loader = loader;
121 }
122
123 pub fn runmat_extensions_enabled(&self) -> bool {
124 self.state.runmat_extensions_enabled.get()
125 }
126
127 pub fn set_runmat_extensions_enabled(&self, enabled: bool) {
128 self.state.runmat_extensions_enabled.set(enabled);
129 }
130
131 pub fn language_mode(&self) -> RuntimeLanguageMode {
132 self.state.language_mode.get()
133 }
134
135 pub fn set_language_mode(&self, mode: RuntimeLanguageMode) {
136 self.state.language_mode.set(mode);
137 }
138
139 pub fn top_level_await_enabled(&self) -> bool {
140 self.state.top_level_await_enabled.get()
141 }
142
143 pub fn set_top_level_await_enabled(&self, enabled: bool) {
144 self.state.top_level_await_enabled.set(enabled);
145 }
146
147 pub fn dynamic_eval_enabled(&self) -> bool {
148 self.state.dynamic_eval_enabled.get()
149 }
150
151 pub fn set_dynamic_eval_enabled(&self, enabled: bool) {
152 self.state.dynamic_eval_enabled.set(enabled);
153 }
154
155 pub fn callstack_limit(&self) -> usize {
156 self.state.callstack_limit.get()
157 }
158
159 pub fn set_callstack_limit(&self, limit: usize) {
160 self.state.callstack_limit.set(limit);
161 }
162
163 pub fn error_namespace(&self) -> String {
164 self.state.error_namespace.borrow().clone()
165 }
166
167 pub fn set_error_namespace(&self, namespace: impl Into<String>) {
168 let namespace = namespace.into();
169 let namespace = if namespace.trim().is_empty() {
170 DEFAULT_ERROR_NAMESPACE.to_string()
171 } else {
172 namespace
173 };
174 *self.state.error_namespace.borrow_mut() = namespace;
175 }
176
177 pub fn with_service_ports(mut self, services: RuntimeServicePorts) -> Self {
178 self.services = services;
179 self
180 }
181
182 pub fn scope<F: Future>(&self, future: F) -> ContextFuture<F> {
185 ContextFuture::new(self.clone(), future)
186 }
187
188 pub fn enter(&self) -> RuntimeContextGuard {
192 RuntimeContextGuard::enter(self.clone())
193 }
194}