klayout_core/component.rs
1//! Components: parameterized cell factories with deterministic param hashing.
2//!
3//! Two-level dedup, both keyed by hash:
4//! 1. `ParamHash` over `Component` args — skip rebuilding identical params.
5//! 2. `ContentHash` over the frozen Cell — dedup cells produced by different
6//! paths that happen to be byte-identical.
7//!
8//! Floats in params must be quantized (e.g. `Microns(i64)` newtype) before
9//! reaching `Hash`. The core does not provide a float-aware hasher on purpose:
10//! quantization should be visible at the call site, not magic.
11
12use crate::cell::CellBuilder;
13use crate::hash::{ParamHash, ParamHasher};
14use crate::library::Library;
15use std::hash::Hash;
16
17pub struct BuildCtx<'a> {
18 pub lib: &'a Library,
19}
20
21impl<'a> BuildCtx<'a> {
22 pub fn new(lib: &'a Library) -> Self {
23 Self { lib }
24 }
25}
26
27pub trait Component: Hash + 'static {
28 fn build(&self, ctx: &BuildCtx<'_>) -> CellBuilder;
29
30 fn param_hash(&self) -> ParamHash {
31 let mut h = ParamHasher::new();
32 // Type name as discriminator so two different Component types with
33 // accidentally-equal Hash payloads don't collide. `type_name` isn't
34 // guaranteed stable across compiler versions, but is stable within a
35 // given build — the dedup cache is per-process anyway.
36 std::hash::Hasher::write(&mut h, std::any::type_name::<Self>().as_bytes());
37 std::hash::Hasher::write_u8(&mut h, 0);
38 Hash::hash(self, &mut h);
39 h.finalize()
40 }
41
42 fn cell_name(&self) -> String {
43 format!(
44 "{}_{}",
45 std::any::type_name::<Self>()
46 .rsplit("::")
47 .next()
48 .unwrap_or("cell"),
49 self.param_hash().short_hex()
50 )
51 }
52}