mysql_handler/runtime/
registry.rs1use std::sync::OnceLock;
26
27use super::context::EngineContext;
28use crate::engine::StorageEngine;
29
30pub type EngineFactory = fn() -> Box<dyn StorageEngine>;
32
33#[derive(Debug)]
38#[non_exhaustive]
39pub(crate) struct EngineRegistry {
40 factory: OnceLock<EngineFactory>,
41}
42
43impl EngineRegistry {
44 pub(crate) const fn new() -> Self {
45 Self {
46 factory: OnceLock::new(),
47 }
48 }
49
50 pub(crate) fn register(&self, factory: EngineFactory) {
51 match self.factory.set(factory) {
52 Ok(()) => {}
53 Err(_) => {
54 tracing::debug!(
55 "engine factory already registered; ignoring duplicate registration"
56 );
57 }
58 }
59 }
60
61 pub(crate) fn create_context(&self) -> Option<EngineContext> {
62 let factory = self.factory.get().copied()?;
63 Some(EngineContext::new(factory()))
64 }
65}
66
67impl Default for EngineRegistry {
68 fn default() -> Self {
69 Self::new()
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use std::ffi::CStr;
76
77 use super::*;
78 use crate::engine::{EngineError, EngineResult};
79
80 struct MockEngine;
81
82 impl StorageEngine for MockEngine {
83 fn table_type(&self) -> &'static CStr {
84 c"MOCK"
85 }
86 fn table_flags(&self) -> u64 {
87 0
88 }
89 fn index_flags(&self, _idx: u32, _part: u32, _all_parts: bool) -> u32 {
90 0
91 }
92 fn create(
93 &mut self,
94 _name: &str,
95 _table_def: Option<&crate::sys::DdTable>,
96 ) -> EngineResult {
97 Ok(())
98 }
99 fn open(
100 &mut self,
101 _name: &str,
102 _mode: i32,
103 _table_def: Option<&crate::sys::DdTable>,
104 ) -> EngineResult {
105 Ok(())
106 }
107 fn close(&mut self) -> EngineResult {
108 Ok(())
109 }
110 fn rnd_init(&mut self, _scan: bool) -> EngineResult {
111 Ok(())
112 }
113 fn rnd_next(&mut self, _buf: &mut [u8]) -> EngineResult {
114 Err(EngineError::EndOfFile)
115 }
116 fn rnd_pos(&mut self, _buf: &mut [u8], _pos: &[u8]) -> EngineResult {
117 Err(EngineError::WrongCommand)
118 }
119 fn position(&mut self, _record: &[u8], _ref_out: &mut [u8]) {}
120 fn info(&mut self, _flag: u32) -> EngineResult {
121 Ok(())
122 }
123 }
124
125 #[test]
126 fn create_context_is_none_before_register() {
127 let registry = EngineRegistry::new();
128 assert!(registry.create_context().is_none());
129 }
130
131 #[test]
132 fn register_then_create_yields_context() {
133 let registry = EngineRegistry::new();
134 registry.register(|| Box::new(MockEngine));
135 assert!(registry.create_context().is_some());
136 }
137
138 #[test]
139 fn duplicate_register_is_ignored() {
140 let registry = EngineRegistry::new();
141 registry.register(|| Box::new(MockEngine));
142 registry.register(|| Box::new(MockEngine));
143 assert!(registry.create_context().is_some());
144 }
145}