Description
Today, when we open a store, we always go directly from a StoreReference
to the <name>Store
data type directly, creating a (typed, per store) <name>StoreConfig
merely in the process. Instead, we should also create the <name>StoreConfig
as a separate step, and then create the store from it.
Here's what needs to be done for that to work:
1. Make sure every <name>StoreConfig
has a (scheme, authority, params)
constructor
Right now, they just have params
(single argument) constructors. This is still needed for the docs, but it should not be the only option. There should also be three-argument constructors as described above.
In order for us to actually make use of the other parameters, any fields which store the scheme
and authority
(if they are side-effect-less!!) should be moved from the corresponding <name>Store
to <name>StoreConfig
. For example, host
should be moved from SSHStore
and LegacySSHStore
to SSHStoreConfig
and LegacySSHStoreConfig
. (And actually we can do a dedup by again moving that field to CommonSSHStoreConfig
, where both type can share it.)
2. *StoreConfig
should be member not base class
Right now, every <Name>Store
type has its <Name>StoreConfig
as a virtual base class. This won't because Config
cannot be copied/moved (due to silly reasons, but let's ignore that) so we cannot initialize a *Store
from a pe-eexisting *StoreConfig
.
To solve this problem we should switch from inheritance to fields. In particular, every one of these *Store
-> *StoreConfig
virtual base classes should become a ref<FooConfig> fooConfig;
. ref<..>
is a crucial choice --- it works with upcasting such that from one RootStoreConfig
allocation we can create as many ref<BaseClassStoreConfig>
as we need, without creating redundant fresh allocations / more configs that could get out of sync (and waste space, but that's not so bad.)
Do note that its only the *Store
-> *StoreConfig
edges which should become fields instead. the *StoreConfig
-> *StoreConfig
and *Store
-> *Store
edges should stay as virtual
inheritance --- for now, at least ;).
3. NameStore::NameStore(ref<NameStoreConfig>)
constructors
With the previous steps done, we change the actual store constructors (replacing the old ones) to not take `(scheme, authority, params), but instead take the corresponding config type (by a shared reference). This should be relatively straightforward so long as everything in the previous step was done properly.
4. openStore
pure virtual method
We can create a new virtual ref<Store> openStore() = 0;
method on StoreConfig
itself. This method's implementations will just call the constructors we modified in the last step with shared_from_this
on the <Name>StoreConfig
(to get the ref<....>
) with make_ref<...>(....)
.
This method does no work on its own (it just calls the constructors) but finishes "proving" that the (concrete, non abstract) <Name>StoreConfig
and <Name>Store
types are actually 1-1 --- for every store type, the constructor chooses a store config type, and for every store config type, the openStore
method chooses a store type, and this is a bijection.
5. Update the store registration machinery
The store registration machinery already registers each pair of store and store config types. But we'll need to fix it to deal with the interface changes from above. Instead of trying to directly construct the store with the matching scheme, it could first construct the store config and then call openStore
on that.
Actually, we should go one step further, the registration machinery should just look up the right store config type, and construct a ref<StoreConfig>
then the user can construct a ref<Store>
from that with our new openStore
method. The registration machinery can only know about store config types, and no longer needs to know about store types at all!