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;
24
25pub type Maker = fn() -> Box<dyn ComponentNode>;
28
29#[derive(Default)]
38pub struct RustdvComp {
39 inner: Option<Box<dyn ComponentNode>>,
40 overridable: bool,
42 requested: Option<&'static str>,
44}
45
46impl RustdvComp {
47 pub fn fixed(node: Box<dyn ComponentNode>) -> RustdvComp {
49 RustdvComp { inner: Some(node), overridable: false, requested: None }
50 }
51
52 pub fn overridable(node: Box<dyn ComponentNode>, requested: &'static str) -> RustdvComp {
55 RustdvComp { inner: Some(node), overridable: true, requested: Some(requested) }
56 }
57
58 pub fn as_node(&self) -> Option<&(dyn ComponentNode + 'static)> {
61 self.inner.as_deref()
62 }
63
64 pub fn as_node_mut(&mut self) -> Option<&mut (dyn ComponentNode + 'static)> {
68 self.inner.as_deref_mut()
69 }
70
71 pub fn take_node(&mut self) -> Option<Box<dyn ComponentNode>> {
82 self.inner.take()
83 }
84
85 pub fn put_node(&mut self, node: Box<dyn ComponentNode>) {
87 self.inner = Some(node);
88 }
89
90 pub fn resolve(&mut self, ctx: &RustdvCtx, name: &str) {
95 if !self.overridable {
96 return;
97 }
98 let Some(req) = self.requested else { return };
99 let path = if ctx.path().is_empty() {
100 name.to_string()
101 } else {
102 format!("{}.{}", ctx.path(), name)
103 };
104 if let Some(ov) = Factory::lookup_override(req, &path) {
105 self.inner = Some((ov.make)());
106 }
107 self.overridable = false;
108 }
109}
110
111impl PortOwner for RustdvComp {
117 fn owner_port_slot(&self, name: &str) -> Option<std::rc::Rc<dyn std::any::Any>> {
118 self.as_node()?.port_slot(name)
119 }
120 fn owner_label(&self) -> &'static str {
121 match self.as_node() {
122 Some(n) => n.node_name(),
123 None => "an unbuilt child slot",
126 }
127 }
128}
129
130#[derive(Clone, Copy)]
136pub struct Override {
137 make: Maker,
138 to: &'static str,
139}
140
141impl fmt::Debug for Override {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 write!(f, "-> {}", self.to)
144 }
145}
146
147fn override_key(requested_name: &str) -> String {
148 format!("__factory_override__{requested_name}")
149}
150
151pub struct ComponentReg {
164 pub name: fn() -> &'static str,
167 pub make: Maker,
168}
169
170fn sentinel_name() -> &'static str {
171 "__rustdv_component_sentinel"
172}
173fn sentinel_make() -> Box<dyn ComponentNode> {
174 panic!("the component-registry sentinel must never be built")
175}
176
177#[used]
178#[cfg_attr(not(target_vendor = "apple"), link_section = "rustdv_comps")]
179#[cfg_attr(target_vendor = "apple", link_section = "__DATA,rustdv_comps")]
180static SENTINEL: &ComponentReg = &ComponentReg { name: sentinel_name, make: sentinel_make };
181
182#[cfg(not(target_vendor = "apple"))]
183extern "C" {
184 static __start_rustdv_comps: u8;
185 static __stop_rustdv_comps: u8;
186}
187#[cfg(target_vendor = "apple")]
188extern "C" {
189 #[link_name = "\x01section$start$__DATA$rustdv_comps"]
190 static __start_rustdv_comps: u8;
191 #[link_name = "\x01section$end$__DATA$rustdv_comps"]
192 static __stop_rustdv_comps: u8;
193}
194
195fn collect_registry() -> HashMap<&'static str, Maker> {
196 std::hint::black_box(SENTINEL.name);
197 let mut map = HashMap::new();
198 unsafe {
199 let start = std::ptr::addr_of!(__start_rustdv_comps) as usize;
200 let stop = std::ptr::addr_of!(__stop_rustdv_comps) as usize;
201 let step = std::mem::size_of::<&ComponentReg>();
202 let base = start as *const &'static ComponentReg;
203 for i in 0..((stop - start) / step) {
204 let reg = *base.add(i);
205 let name = (reg.name)();
206 if name != sentinel_name() {
207 map.insert(name, reg.make);
208 }
209 }
210 }
211 map
212}
213
214thread_local! {
215 static REGISTRY: RefCell<Option<HashMap<&'static str, Maker>>> = const { RefCell::new(None) };
218}
219
220fn with_registry<R>(f: impl FnOnce(&HashMap<&'static str, Maker>) -> R) -> R {
221 REGISTRY.with(|r| {
222 let mut slot = r.borrow_mut();
223 if slot.is_none() {
224 *slot = Some(collect_registry());
225 }
226 f(slot.as_ref().unwrap())
227 })
228}
229
230pub struct Factory;
237
238impl Factory {
239 pub fn create_by_name(name: &str) -> RustdvComp {
244 let make = with_registry(|reg| reg.get(name).copied());
245 match make {
246 Some(make) => {
247 let stored = with_registry(|reg| reg.keys().find(|k| **k == name).copied());
250 RustdvComp::overridable(make(), stored.expect("just found it"))
251 }
252 None => panic!("Factory::create_by_name: no component registered as \"{name}\""),
253 }
254 }
255
256 pub fn set_type_override<From, To>()
260 where
261 From: Component + ComponentNode + Default + 'static,
262 To: Component + ComponentNode + Default + 'static,
263 {
264 Self::store_override(None, "*", From::comp_name(), To::comp_name(), || {
265 Box::new(To::default())
266 });
267 }
268
269 pub fn set_type_override_by_name(from: &str, to: &str) {
272 let make = with_registry(|reg| reg.get(to).copied())
273 .unwrap_or_else(|| panic!("Factory::set_type_override_by_name: \"{to}\" is not registered"));
274 let to_static = with_registry(|reg| reg.keys().find(|k| **k == to).copied()).expect("just found it");
275 Self::store_override(None, "*", from, to_static, make);
276 }
277
278 pub fn set_inst_override<From, To>(ctx: &RustdvCtx, path: &str)
283 where
284 From: Component + ComponentNode + Default + 'static,
285 To: Component + ComponentNode + Default + 'static,
286 {
287 Self::store_override(Some(ctx), path, From::comp_name(), To::comp_name(), || {
288 Box::new(To::default())
289 });
290 }
291
292 fn store_override(
293 ctx: Option<&RustdvCtx>,
294 offset: &str,
295 from_name: &str,
296 to_name: &'static str,
297 make: Maker,
298 ) {
299 ConfigDb::set(ctx, offset, &override_key(from_name), Override { make, to: to_name });
300 }
301
302 pub(crate) fn lookup_override(requested_name: &str, abs_path: &str) -> Option<Override> {
304 ConfigDb::get::<Override>(None, abs_path, &override_key(requested_name)).ok()
305 }
306
307 pub fn print() {
310 rustdv_sim::log::info("Factory overrides:");
311 for (path, from, to) in ConfigDb::factory_overrides() {
312 rustdv_sim::log::info(&format!(" {path:<28}: {from} -> {to}"));
313 }
314 }
315}
316
317#[cfg(test)]
322mod tests {
323 use super::*;
324 use crate::component::{Component, RustdvCtx};
325 use crate::config::ConfigDb;
326 use std::cell::RefCell;
327 use std::rc::Rc;
328
329 thread_local! {
330 static BUILT: RefCell<Vec<&'static str>> = const { RefCell::new(Vec::new()) };
331 }
332
333 fn record(name: &'static str) {
334 BUILT.with(|b| b.borrow_mut().push(name));
335 }
336
337 #[derive(Default)]
338 struct Base;
339 impl Component for Base {
340 fn build(&mut self, _ctx: &mut RustdvCtx) {
341 record("Base");
342 }
343 }
344 impl ComponentNode for Base {
345 fn node_name(&self) -> &'static str {
346 "Base"
347 }
348 fn children_mut(&mut self) -> Vec<(String, &mut (dyn ComponentNode + 'static))> {
349 Vec::new()
350 }
351 }
352
353 #[derive(Default)]
354 struct Derived;
355 impl Component for Derived {
356 fn build(&mut self, _ctx: &mut RustdvCtx) {
357 record("Derived");
358 }
359 }
360 impl ComponentNode for Derived {
361 fn node_name(&self) -> &'static str {
362 "Derived"
363 }
364 fn children_mut(&mut self) -> Vec<(String, &mut (dyn ComponentNode + 'static))> {
365 Vec::new()
366 }
367 }
368
369 fn fresh() {
370 ConfigDb::clear();
371 BUILT.with(|b| b.borrow_mut().clear());
372 }
373
374 #[test]
375 fn a_fixed_slot_holds_what_it_was_given() {
376 fresh();
377 let slot = RustdvComp::fixed(Box::new(Base));
378 assert_eq!(slot.as_node().unwrap().node_name(), "Base");
379 }
380
381 #[test]
382 fn an_empty_slot_reports_itself_by_name() {
383 fresh();
384 let slot = RustdvComp::default();
385 assert!(slot.as_node().is_none());
386 assert_eq!(slot.owner_label(), "an unbuilt child slot");
387 }
388
389 #[test]
392 fn a_type_override_swaps_a_create_slot_and_not_a_new_slot() {
393 fresh();
394 Factory::set_type_override::<Base, Derived>();
395 let ctx = RustdvCtx::for_test("env");
396
397 let mut overridable = RustdvComp::overridable(Box::new(Base), "Base");
398 overridable.resolve(&ctx, "tester");
399 assert_eq!(overridable.as_node().unwrap().node_name(), "Derived");
400
401 let mut fixed = RustdvComp::fixed(Box::new(Base));
402 fixed.resolve(&ctx, "scoreboard");
403 assert_eq!(fixed.as_node().unwrap().node_name(), "Base", "new_comp is never swapped");
404 }
405
406 #[test]
407 fn no_override_leaves_the_requested_type() {
408 fresh();
409 let ctx = RustdvCtx::for_test("env");
410 let mut slot = RustdvComp::overridable(Box::new(Base), "Base");
411 slot.resolve(&ctx, "tester");
412 assert_eq!(slot.as_node().unwrap().node_name(), "Base");
413 }
414
415 #[test]
418 fn an_instance_override_beats_a_type_override() {
419 fresh();
420 let ctx = RustdvCtx::for_test("env");
421 Factory::set_type_override::<Base, Base>();
422 Factory::set_inst_override::<Base, Derived>(&ctx, "tester");
423 let mut slot = RustdvComp::overridable(Box::new(Base), "Base");
424 slot.resolve(&ctx, "tester");
425 assert_eq!(slot.as_node().unwrap().node_name(), "Derived");
426 }
427
428 #[test]
429 fn an_instance_override_applies_only_at_its_path() {
430 fresh();
431 let ctx = RustdvCtx::for_test("env");
432 Factory::set_inst_override::<Base, Derived>(&ctx, "tester");
433
434 let mut here = RustdvComp::overridable(Box::new(Base), "Base");
435 here.resolve(&ctx, "tester");
436 assert_eq!(here.as_node().unwrap().node_name(), "Derived");
437
438 let mut elsewhere = RustdvComp::overridable(Box::new(Base), "Base");
439 elsewhere.resolve(&ctx, "other");
440 assert_eq!(elsewhere.as_node().unwrap().node_name(), "Base");
441 }
442
443 #[test]
446 fn the_discarded_default_never_built() {
447 fresh();
448 Factory::set_type_override::<Base, Derived>();
449 let ctx = RustdvCtx::for_test("env");
450 let mut slot = RustdvComp::overridable(Box::new(Base), "Base");
451 slot.resolve(&ctx, "tester");
452 assert_eq!(BUILT.with(|b| b.borrow().len()), 0);
455 assert_eq!(slot.as_node().unwrap().node_name(), "Derived");
456 }
457
458 #[test]
461 fn a_slot_resolves_once() {
462 fresh();
463 let ctx = RustdvCtx::for_test("env");
464 let mut slot = RustdvComp::overridable(Box::new(Base), "Base");
465 slot.resolve(&ctx, "tester");
466 Factory::set_type_override::<Base, Derived>(); slot.resolve(&ctx, "tester");
468 assert_eq!(
469 slot.as_node().unwrap().node_name(),
470 "Base",
471 "an override installed after the walk passed does not apply"
472 );
473 }
474
475 #[test]
476 fn take_and_put_move_the_box_out_and_back() {
477 fresh();
478 let mut slot = RustdvComp::fixed(Box::new(Base));
479 let node = slot.take_node().expect("something to take");
480 assert!(slot.as_node().is_none(), "the slot is empty during the run phase");
481 slot.put_node(node);
482 assert_eq!(slot.as_node().unwrap().node_name(), "Base", "and restored after");
483 }
484
485 use crate::sequence::{clear_seq_overrides, create_seq, set_seq_override, SeqCtx, SeqError, Sequence};
488
489 #[derive(Default)]
490 struct BaseSeq;
491 #[derive(Default)]
492 struct RandomSeq;
493
494 impl Sequence for BaseSeq {
495 type Req = u8;
496 type Rsp = u8;
497 async fn body(&mut self, _c: &mut SeqCtx<u8, u8>) -> Result<(), SeqError> {
498 Ok(())
499 }
500 fn seq_name(&self) -> &'static str {
501 "BaseSeq"
502 }
503 }
504 impl Sequence for RandomSeq {
505 type Req = u8;
506 type Rsp = u8;
507 async fn body(&mut self, _c: &mut SeqCtx<u8, u8>) -> Result<(), SeqError> {
508 Ok(())
509 }
510 fn seq_name(&self) -> &'static str {
511 "RandomSeq"
512 }
513 }
514
515 #[test]
516 fn create_seq_builds_the_requested_type_by_default() {
517 clear_seq_overrides();
518 let seq = create_seq::<BaseSeq>();
519 assert_eq!(seq.name(), "BaseSeq");
520 }
521
522 #[test]
523 fn a_sequence_override_swaps_the_type() {
524 clear_seq_overrides();
525 set_seq_override::<BaseSeq, RandomSeq>();
526 let seq = create_seq::<BaseSeq>();
527 assert_eq!(seq.name(), "RandomSeq", "the test asked for Base and got Random");
528 }
529
530 #[test]
531 fn clearing_sequence_overrides_restores_the_default() {
532 clear_seq_overrides();
533 set_seq_override::<BaseSeq, RandomSeq>();
534 clear_seq_overrides();
535 assert_eq!(create_seq::<BaseSeq>().name(), "BaseSeq");
536 }
537
538 #[test]
539 fn an_override_on_one_sequence_leaves_others_alone() {
540 clear_seq_overrides();
541 set_seq_override::<BaseSeq, RandomSeq>();
542 assert_eq!(create_seq::<RandomSeq>().name(), "RandomSeq");
543 }
544
545 #[allow(dead_code)]
547 fn _rc_in_scope(_: Rc<u8>) {}
548}