Add initial support component metadata supplier caching
This commit adds the infrastructure for caching of component metadata rules.
For now, the only kind of rule we can cache are the component metadata supplier
rules, which are used during dynamic version selection, but the executor
infrastructure can be reused to cache more kinds of rules.
The implementation relies on the principal that a "rule" can be safely cached if:
- the rule has no side effect, and uses the "class-based pattern"
- the implementation of the rule didn't change
- the inputs of the rule didn't change
For this, we introduce a new persistent cache (hence cross-build) with an in-memory
facing cache, that allows us to avoid the execution of a rule if the result is
already in the cache. The implementation makes use of _snapshotting_ to capture the
state of the inputs of a rule, which consists of the implementation of the rule and
its potential parameters. It's worth noting that at this stage we do not consider
the services the rule can use, it's going to be done in a subsequent commit.
This worked required a clarification of what an rule cares about (the result) in
opposition to what the user is faced with. For example, a component metadata supplier
rule output is a `ComponentMetadata`, but what we offer to the user, to build that
metadata, is a `ComponentMetadataSupplierDetails` instance. Similarly, component
metadata rules would have different kind of output and what the user manipulates.
The cache works with a primary key (for the first implemented cache, the key is the
module version identifier) and will invalidate the results based on the cache policy
(should refresh modules).
The persistent cache uses the snapshot as the key in the store. In theory, should we
consider that we have a nearly perfect hash function, we could instead use the hash
of the snapshot as the key. Measurements would have to be made to check if it's worth
implementing.