Skip to content

[Task] Find a replacement for feature gated trait methods  #923

Open
@olivereanderson

Description

@olivereanderson

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:

  1. It is not additive meaning that it can break compilation for downstream crates. Here is an example: crate foo depends on identity_account_storage without the encryption feature and implements Storage for one of its types. Another crate bar depends on identity_account_storage with the encryption feature. Then if ever bar becomes part of foo's dependency tree, foo will no longer compile.
  2. 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 Accounts some using fancy storage backends and others less so. If the encryption 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

No one assigned

    Labels

    Breaking changeA change to the API that requires a major release. Part of "Changed" section in changelogRustRelated to the core Rust code. Becomes part of the Rust changelog.

    Type

    No type

    Projects

    Status

    Product Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions