Description
Description
Currently the Storage
trait contains certain methods (such as for instance data_encrypt
) that are feature gated. We should consider finding an alternative way of allowing users to opt in to implementing these methods on their storage backends. See the Motivation section below for why an alternative is desirable.
The Implementation suggestions section discusses a few ways to proceed.
Motivation
Feature gating trait methods is problematic for the following reasons:
- It is not additive meaning that it can break compilation for downstream crates. Here is an example: crate
foo
depends onidentity_account_storage
without theencryption
feature and implementsStorage
for one of its types. Another cratebar
depends onidentity_account_storage
with theencryption
feature. Then if everbar
becomes part offoo
's dependency tree,foo
will no longer compile. - If a library consumer wants to implement said feature gated trait methods for at least one of its types, then said methods need to be implemented on every type implementing the trait regardless of whether its needed. As an example someone might have an application with different kinds of
Account
s some using fancy storage backends and others less so. If theencryption
flag is set they are also forced to implement these methods for their more rudimentary storage types.
Implementation suggestions
The alternative that is easiest to implement would be to simply always include these methods on the Storage
trait and provide a default implementation that simply returns a "operation not supported" error that the user my overwrite themselves. Although simple this approach is perhaps not the most elegant.
Another way to approach this would be via generics. Roughly speaking we could do something like: introduce a feature gated sub-trait StorageEncryption: Storage
which contains encrypt/decrypt_data
methods and add an additional generic parameter to the Account
. So it would be (something like) Account<C = Arc<Client>, T: Storage>
and make the encrypt/decrypt
methods available in an impl block :
#[cfg(feature = "encryption")]
impl <C: SharedPtr, T: StorageEncryption> Account<C,T > {
pub fn encrypt_data;
pub fn decrypt_data;
}
. Note that this is just a rough sketch and doing this properly would require some thought. In my understanding the bindings require dynamic dispatch and this would have to be supported somehow (I am pretty sure it can be done). However even if we manage to implement this approach "correctly" we might still have to force our API to require more type annotations (turbofish) which is not ideal.
Resources
Blocked by #920
To-do list
- Implement an alternative to feature gating methods in the
Storage
trait. - Investigate whether there are more instances of feature gated methods in traits throughout the code base and open issues to address them.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status