Skip to main content

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}