1use std::cell::RefCell;
18use std::collections::HashMap;
19use std::fmt;
20
21use crate::component::{Component, ComponentNode, RustdvCtx};
22use crate::config::ConfigDb;
23use crate::port::PortOwner;
24use linkme::distributed_slice;
25
26pub type Maker = fn() -> Box<dyn ComponentNode>;
29
30#[derive(Default)]
39pub struct RustdvComp {
40 inner: Option<Box<dyn ComponentNode>>,
41 overridable: bool,
43 requested: Option<&'static str>,
45}
46
47impl RustdvComp {
48 pub fn fixed(node: Box<dyn ComponentNode>) -> RustdvComp {
50 RustdvComp {
51 inner: Some(node),
52 overridable: false,
53 requested: None,
54 }
55 }
56
57 pub fn overridable(node: Box<dyn ComponentNode>, requested: &'static str) -> RustdvComp {
60 RustdvComp {
61 inner: Some(node),
62 overridable: true,
63 requested: Some(requested),
64 }
65 }
66
67 pub fn as_node(&self) -> Option<&(dyn ComponentNode + 'static)> {
70 self.inner.as_deref()
71 }
72
73 pub fn as_node_mut(&mut self) -> Option<&mut (dyn ComponentNode + 'static)> {
77 self.inner.as_deref_mut()
78 }
79
80 pub fn take_node(&mut self) -> Option<Box<dyn ComponentNode>> {
91 self.inner.take()
92 }
93
94 pub fn put_node(&mut self, node: Box<dyn ComponentNode>) {
96 self.inner = Some(node);
97 }
98
99 pub fn resolve(&mut self, ctx: &RustdvCtx, name: &str) {
104 if !self.overridable {
105 return;
106 }
107 let Some(req) = self.requested else { return };
108 let path = if ctx.path().is_empty() {
109 name.to_string()
110 } else {
111 format!("{}.{}", ctx.path(), name)
112 };
113 if let Some(ov) = Factory::lookup_override(req, &path) {
114 self.inner = Some((ov.make)());
115 }
116 self.overridable = false;
117 }
118}
119
120impl PortOwner for RustdvComp {
126 fn owner_port_slot(&self, name: &str) -> Option<std::rc::Rc<dyn std::any::Any>> {
127 self.as_node()?.port_slot(name)
128 }
129 fn owner_label(&self) -> &'static str {
130 match self.as_node() {
131 Some(n) => n.node_name(),
132 None => "an unbuilt child slot",
135 }
136 }
137}
138
139#[derive(Clone, Copy)]
145pub struct Override {
146 make: Maker,
147 to: &'static str,
148}
149
150impl fmt::Debug for Override {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 write!(f, "-> {}", self.to)
153 }
154}
155
156fn override_key(requested_name: &str) -> String {
157 format!("__factory_override__{requested_name}")
158}
159
160pub struct ComponentReg {
168 pub name: fn() -> &'static str,
171 pub make: Maker,
172}
173
174#[doc(hidden)]
178#[distributed_slice]
179pub static COMPONENT_REGISTRATIONS: [ComponentReg];
180
181fn collect_registry() -> HashMap<&'static str, Maker> {
182 let mut map = HashMap::new();
183 for reg in COMPONENT_REGISTRATIONS {
184 map.insert((reg.name)(), reg.make);
185 }
186 map
187}
188
189thread_local! {
190 static REGISTRY: RefCell<Option<HashMap<&'static str, Maker>>> = const { RefCell::new(None) };
193}
194
195fn with_registry<R>(f: impl FnOnce(&HashMap<&'static str, Maker>) -> R) -> R {
196 REGISTRY.with(|r| {
197 let mut slot = r.borrow_mut();
198 if slot.is_none() {
199 *slot = Some(collect_registry());
200 }
201 f(slot.as_ref().unwrap())
202 })
203}
204
205pub struct Factory;
212
213impl Factory {
214 pub fn create_by_name(name: &str) -> RustdvComp {
219 let make = with_registry(|reg| reg.get(name).copied());
220 match make {
221 Some(make) => {
222 let stored = with_registry(|reg| reg.keys().find(|k| **k == name).copied());
225 RustdvComp::overridable(make(), stored.expect("just found it"))
226 }
227 None => panic!("Factory::create_by_name: no component registered as \"{name}\""),
228 }
229 }
230
231 pub fn set_type_override<From, To>()
235 where
236 From: Component + ComponentNode + Default + 'static,
237 To: Component + ComponentNode + Default + 'static,
238 {
239 Self::store_override(None, "*", From::comp_name(), To::comp_name(), || {
240 Box::new(To::default())
241 });
242 }
243
244 pub fn set_type_override_by_name(from: &str, to: &str) {
247 let make = with_registry(|reg| reg.get(to).copied()).unwrap_or_else(|| {
248 panic!("Factory::set_type_override_by_name: \"{to}\" is not registered")
249 });
250 let to_static =
251 with_registry(|reg| reg.keys().find(|k| **k == to).copied()).expect("just found it");
252 Self::store_override(None, "*", from, to_static, make);
253 }
254
255 pub fn set_inst_override<From, To>(ctx: &RustdvCtx, path: &str)
260 where
261 From: Component + ComponentNode + Default + 'static,
262 To: Component + ComponentNode + Default + 'static,
263 {
264 Self::store_override(Some(ctx), path, From::comp_name(), To::comp_name(), || {
265 Box::new(To::default())
266 });
267 }
268
269 fn store_override(
270 ctx: Option<&RustdvCtx>,
271 offset: &str,
272 from_name: &str,
273 to_name: &'static str,
274 make: Maker,
275 ) {
276 ConfigDb::set(
277 ctx,
278 offset,
279 &override_key(from_name),
280 Override { make, to: to_name },
281 );
282 }
283
284 pub(crate) fn lookup_override(requested_name: &str, abs_path: &str) -> Option<Override> {
286 ConfigDb::get::<Override>(None, abs_path, &override_key(requested_name)).ok()
287 }
288
289 pub fn print() {
292 rustdv_sim::log::info("Factory overrides:");
293 for (path, from, to) in ConfigDb::factory_overrides() {
294 rustdv_sim::log::info(&format!(" {path:<28}: {from} -> {to}"));
295 }
296 }
297}
298
299#[cfg(test)]
304mod tests {
305 use super::*;
306 use crate::component::{Component, RustdvCtx};
307 use crate::config::ConfigDb;
308 use std::cell::RefCell;
309 use std::rc::Rc;
310
311 thread_local! {
312 static BUILT: RefCell<Vec<&'static str>> = const { RefCell::new(Vec::new()) };
313 }
314
315 fn record(name: &'static str) {
316 BUILT.with(|b| b.borrow_mut().push(name));
317 }
318
319 #[derive(Default)]
320 struct Base;
321 impl Component for Base {
322 fn build(&mut self, _ctx: &mut RustdvCtx) {
323 record("Base");
324 }
325 }
326 impl ComponentNode for Base {
327 fn node_name(&self) -> &'static str {
328 "Base"
329 }
330 fn children_mut(&mut self) -> Vec<(String, &mut (dyn ComponentNode + 'static))> {
331 Vec::new()
332 }
333 }
334
335 #[derive(Default)]
336 struct Derived;
337 impl Component for Derived {
338 fn build(&mut self, _ctx: &mut RustdvCtx) {
339 record("Derived");
340 }
341 }
342 impl ComponentNode for Derived {
343 fn node_name(&self) -> &'static str {
344 "Derived"
345 }
346 fn children_mut(&mut self) -> Vec<(String, &mut (dyn ComponentNode + 'static))> {
347 Vec::new()
348 }
349 }
350
351 fn fresh() {
352 ConfigDb::clear();
353 BUILT.with(|b| b.borrow_mut().clear());
354 }
355
356 #[test]
357 fn a_fixed_slot_holds_what_it_was_given() {
358 fresh();
359 let slot = RustdvComp::fixed(Box::new(Base));
360 assert_eq!(slot.as_node().unwrap().node_name(), "Base");
361 }
362
363 #[test]
364 fn an_empty_slot_reports_itself_by_name() {
365 fresh();
366 let slot = RustdvComp::default();
367 assert!(slot.as_node().is_none());
368 assert_eq!(slot.owner_label(), "an unbuilt child slot");
369 }
370
371 #[test]
374 fn a_type_override_swaps_a_create_slot_and_not_a_new_slot() {
375 fresh();
376 Factory::set_type_override::<Base, Derived>();
377 let ctx = RustdvCtx::for_test("env");
378
379 let mut overridable = RustdvComp::overridable(Box::new(Base), "Base");
380 overridable.resolve(&ctx, "tester");
381 assert_eq!(overridable.as_node().unwrap().node_name(), "Derived");
382
383 let mut fixed = RustdvComp::fixed(Box::new(Base));
384 fixed.resolve(&ctx, "scoreboard");
385 assert_eq!(
386 fixed.as_node().unwrap().node_name(),
387 "Base",
388 "new_comp is never swapped"
389 );
390 }
391
392 #[test]
393 fn no_override_leaves_the_requested_type() {
394 fresh();
395 let ctx = RustdvCtx::for_test("env");
396 let mut slot = RustdvComp::overridable(Box::new(Base), "Base");
397 slot.resolve(&ctx, "tester");
398 assert_eq!(slot.as_node().unwrap().node_name(), "Base");
399 }
400
401 #[test]
404 fn an_instance_override_beats_a_type_override() {
405 fresh();
406 let ctx = RustdvCtx::for_test("env");
407 Factory::set_type_override::<Base, Base>();
408 Factory::set_inst_override::<Base, Derived>(&ctx, "tester");
409 let mut slot = RustdvComp::overridable(Box::new(Base), "Base");
410 slot.resolve(&ctx, "tester");
411 assert_eq!(slot.as_node().unwrap().node_name(), "Derived");
412 }
413
414 #[test]
415 fn an_instance_override_applies_only_at_its_path() {
416 fresh();
417 let ctx = RustdvCtx::for_test("env");
418 Factory::set_inst_override::<Base, Derived>(&ctx, "tester");
419
420 let mut here = RustdvComp::overridable(Box::new(Base), "Base");
421 here.resolve(&ctx, "tester");
422 assert_eq!(here.as_node().unwrap().node_name(), "Derived");
423
424 let mut elsewhere = RustdvComp::overridable(Box::new(Base), "Base");
425 elsewhere.resolve(&ctx, "other");
426 assert_eq!(elsewhere.as_node().unwrap().node_name(), "Base");
427 }
428
429 #[test]
432 fn the_discarded_default_never_built() {
433 fresh();
434 Factory::set_type_override::<Base, Derived>();
435 let ctx = RustdvCtx::for_test("env");
436 let mut slot = RustdvComp::overridable(Box::new(Base), "Base");
437 slot.resolve(&ctx, "tester");
438 assert_eq!(BUILT.with(|b| b.borrow().len()), 0);
441 assert_eq!(slot.as_node().unwrap().node_name(), "Derived");
442 }
443
444 #[test]
447 fn a_slot_resolves_once() {
448 fresh();
449 let ctx = RustdvCtx::for_test("env");
450 let mut slot = RustdvComp::overridable(Box::new(Base), "Base");
451 slot.resolve(&ctx, "tester");
452 Factory::set_type_override::<Base, Derived>(); slot.resolve(&ctx, "tester");
454 assert_eq!(
455 slot.as_node().unwrap().node_name(),
456 "Base",
457 "an override installed after the walk passed does not apply"
458 );
459 }
460
461 #[test]
462 fn take_and_put_move_the_box_out_and_back() {
463 fresh();
464 let mut slot = RustdvComp::fixed(Box::new(Base));
465 let node = slot.take_node().expect("something to take");
466 assert!(
467 slot.as_node().is_none(),
468 "the slot is empty during the run phase"
469 );
470 slot.put_node(node);
471 assert_eq!(
472 slot.as_node().unwrap().node_name(),
473 "Base",
474 "and restored after"
475 );
476 }
477
478 use crate::sequence::{
481 SeqCtx, SeqError, Sequence, clear_seq_overrides, create_seq, set_seq_override,
482 };
483
484 #[derive(Default)]
485 struct BaseSeq;
486 #[derive(Default)]
487 struct RandomSeq;
488
489 impl Sequence for BaseSeq {
490 type Req = u8;
491 type Rsp = u8;
492 async fn body(&mut self, _c: &mut SeqCtx<u8, u8>) -> Result<(), SeqError> {
493 Ok(())
494 }
495 fn seq_name(&self) -> &'static str {
496 "BaseSeq"
497 }
498 }
499 impl Sequence for RandomSeq {
500 type Req = u8;
501 type Rsp = u8;
502 async fn body(&mut self, _c: &mut SeqCtx<u8, u8>) -> Result<(), SeqError> {
503 Ok(())
504 }
505 fn seq_name(&self) -> &'static str {
506 "RandomSeq"
507 }
508 }
509
510 #[test]
511 fn create_seq_builds_the_requested_type_by_default() {
512 clear_seq_overrides();
513 let seq = create_seq::<BaseSeq>();
514 assert_eq!(seq.name(), "BaseSeq");
515 }
516
517 #[test]
518 fn a_sequence_override_swaps_the_type() {
519 clear_seq_overrides();
520 set_seq_override::<BaseSeq, RandomSeq>();
521 let seq = create_seq::<BaseSeq>();
522 assert_eq!(
523 seq.name(),
524 "RandomSeq",
525 "the test asked for Base and got Random"
526 );
527 }
528
529 #[test]
530 fn clearing_sequence_overrides_restores_the_default() {
531 clear_seq_overrides();
532 set_seq_override::<BaseSeq, RandomSeq>();
533 clear_seq_overrides();
534 assert_eq!(create_seq::<BaseSeq>().name(), "BaseSeq");
535 }
536
537 #[test]
538 fn an_override_on_one_sequence_leaves_others_alone() {
539 clear_seq_overrides();
540 set_seq_override::<BaseSeq, RandomSeq>();
541 assert_eq!(create_seq::<RandomSeq>().name(), "RandomSeq");
542 }
543
544 #[allow(dead_code)]
546 fn _rc_in_scope(_: Rc<u8>) {}
547}