In #413 (closed) and a code comment, I grumbled about NetParams
. Having investigated, my conclusions are as follows.
NetParams<T>
has as its primary use in elements of the state of the dirmgr, tor-netdoc, etc. There are at least two specialisations and various places where this data appears.NetParams<i32>
. For convenience of the code there, it just reuses the NetParams<i32>
as the built (validated) config element. DirMgrConfig
is not a builder struct (for reasons explained in its comments); instead, it is simply a copy of some of the pieces of a TorClientConfig
.TorClientConfig
contains override_net_params: NetParams<i32>
.TorClientConfigBuilder
. The builder (the public API) contains a plain HashMap
and offers an override_net_params()
mut accessor function.So the NetParams
is already not exposed in the primary config API - only in lower levels. The primary config API is precisely to allow the user to build and manipulate a HashMap<String,i32>
. Likewise, we deserialise it as a HashMap
defaulting to empty.
Offering a concrete struct in this way is roughly in line with what we now do for lists, where we offer accessors for a Vec
. However, there is a difference: the Vec
arrangements are capable of having a non-empty default. Here, the semantics of the setting imply that it has an empty default.
Overall I think the choices for the top-level config API here are:
As things are now. Expose a HashMap
directly, with no _opt
etc. (ie no non-empty defaulting). If we want to add config entries in the future which are of this rough shape but with a non-empty default, they might need a more sophisticated API. However, the current API mirrors the one for Vec
s pretty precisely, so I think that future change would be an extension even if we were to retrofit it to override_net_params
.
Build, now, a thing for HashMap
that mirrors the list builder for Vec
. This seems unattractive at this stage, particularly since I think that API would be a superset of what we have now.
Make the builder have a Vec
and offer the list API, even though this is actually a non-ordered set of overrides (or, rather, a set of overrides which honours ordering only in that it forgets earlier settings). This seems quite unattractive, as it would be a misrepresentation of the semantics. And it would either have to be Vec<(String, Option<i32>)>
so that it can support deletion by appending, or deletion would have to be done by filtering even though overriding can be done by appending.
As we have now, but hide the HashMap
behind something with a less rich API. There is an argument for this - our reasoning for Vec
was that Vec
is a very fundamental type in Rust, and this is less so for HashMap
. Nevertheless I don't foresee us wanting to change this.
Of these I prefer (1), the status quo. (2) and (3) are quite unattractive.
NetParams
as both state and validated configFinally, it is sligbhtly anomalous that NetParams<i32>
is both a piece of state and a piece of config. But this is in the lower layers and I don't see any value in separating these types - it would just lead to pointless conversion code. I think comments are fine to address this.
We could add type aliases (eg type NetParamsBuilder<T> = HashMap<String,T>
, but IMO they would confuse and indirect more than they would enlighten.
Therefore I proose here to address #413 (closed) in code comments, and make no other code changes.
Would the reviewer please double check my reasoning above :-). If I have got anything wrong, or you disagree with this resolution, we should talk about it and not merge this MR.