1// -------------------------------------------------------------------------------------------------
2// Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3// https://nautechsystems.io
4//
5// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6// You may not use this file except in compliance with the License.
7// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14// -------------------------------------------------------------------------------------------------
1516use std::{
17 cell::{OnceCell, RefCell},
18 collections::VecDeque,
19 rc::Rc,
20};
2122use nautilus_model::data::Data;
2324use crate::{
25 clock::Clock,
26 messages::data::{DataResponse, SubscribeCommand},
27 timer::TimeEvent,
28};
2930pub trait DataQueue {
31fn push(&mut self, event: DataEvent);
32}
3334pub type GlobalDataQueue = Rc<RefCell<dyn DataQueue>>;
3536// TODO: Refine this to reduce disparity between enum sizes
37#[allow(clippy::large_enum_variant)]
38pub enum DataEvent {
39 Response(DataResponse),
40 Data(Data),
41}
4243pub struct SyncDataQueue(VecDeque<DataEvent>);
4445impl DataQueue for SyncDataQueue {
46fn push(&mut self, event: DataEvent) {
47self.0.push_back(event);
48 }
49}
5051#[must_use]
52pub fn get_data_queue() -> Rc<RefCell<dyn DataQueue>> {
53 DATA_QUEUE
54 .try_with(|dq| {
55 dq.get()
56 .expect("Data queue should be initialized by runner")
57 .clone()
58 })
59 .expect("Should be able to access thread local storage")
60}
6162pub fn set_data_queue(dq: Rc<RefCell<dyn DataQueue>>) {
63 DATA_QUEUE
64 .try_with(|deque| {
65assert!(deque.set(dq).is_ok(), "Global data queue already set");
66 })
67 .expect("Should be able to access thread local storage");
68}
6970pub type GlobalClock = Rc<RefCell<dyn Clock>>;
7172#[must_use]
73pub fn get_clock() -> Rc<RefCell<dyn Clock>> {
74 CLOCK
75 .try_with(|clock| {
76 clock
77 .get()
78 .expect("Clock should be initialized by runner")
79 .clone()
80 })
81 .expect("Should be able to access thread local storage")
82}
8384pub fn set_clock(c: Rc<RefCell<dyn Clock>>) {
85 CLOCK
86 .try_with(|clock| {
87assert!(clock.set(c).is_ok(), "Global clock already set");
88 })
89 .expect("Should be able to access thread local clock");
90}
9192pub type MessageBusCommands = Rc<RefCell<VecDeque<SubscribeCommand>>>; // TODO: Use DataCommand?
9394/// Get globally shared message bus command queue
95#[must_use]
96pub fn get_msgbus_cmd() -> MessageBusCommands {
97 MSGBUS_CMD
98 .try_with(std::clone::Clone::clone)
99 .expect("Should be able to access thread local storage")
100}
101102thread_local! {
103static CLOCK: OnceCell<GlobalClock> = OnceCell::new();
104static DATA_QUEUE: OnceCell<GlobalDataQueue> = OnceCell::new();
105static MSGBUS_CMD: MessageBusCommands = Rc::new(RefCell::new(VecDeque::new()));
106}
107108pub trait SendResponse {
109fn send(&self, resp: DataResponse);
110}
111112pub type DataResponseQueue = Rc<RefCell<SyncDataQueue>>;
113114// Represents different event types for the runner.
115#[allow(clippy::large_enum_variant)]
116pub enum RunnerEvent {
117 Data(DataEvent),
118 Timer(TimeEvent),
119}