You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It's not sustainable to refactor provider into functions every couple months, and function duplication into _with_provider variants adds unnecessary noise. We should figure out a longer-term solution to share provider references without the churn.
One possible solution:
Create a wrapper unit struct that implements XmtpOpenMlsProvider, but holds a Cow<_>. ProviderRef<'_>
ProviderRef will hold an Option<Cow<Provider<'_>>
MlsGroup becomes MlsGroup<'a, Client>
MlsGroup can be aliased to MlsGroup<'static, Client> for the trivial case where it does not yet hold a provider, or the provider is owned. This should make it possible for all external functions to retain their same function signatures, without proliferating a lifetime everywhere in the code
all MlsGroup methods will access a provider through mls_provider() method. Internally, ProviderRef will check for the existence of a provider, and if it exists use the reference. Otherwise, it will pull a new provider
Pros:
simplifies provider management, no more &Provider everywhere, or _with_provider
to use provider can just call mls_provider()
Cons:
could make it trickier to pass a provider down through function codepaths since its hidden behind a unit struct, rather than easily seen from a function signature. This may lead to more opaque error messages about lifetimes
Solution that builds upon this:
we can encapsulate completely the provider management within ProviderRef and pull a new provider if needed within OpenMlsProvider implementation itself. Everywhere we currently accept a provider, we could accept impl OpenMlsProvider or its generic fn<P: OpenMlsProvider>(provider: P) variant. We additionally impement a ProviderExt trait that makes it possible to access Sqlite Connection from this, by appending an additional trait implementation:
This may over-complicate in places for most things esp. with error type management in function callbacks, that would now have to specify something to the effect of
E: From<<P as OpenMlsProvider> as StorageProvider::Error>
which can become more complicated with further nested generics
Rough sketch of Provider Extension Trait
/// This trait would be useful elsewhere too,/// but it would be a large refactor. For now, it is used in `ProcessMessageFuture`/// to accept either a Reference or Owned type./// `as_ref` is a hack to convert back to a concrete type./// In the future, we can replace function arguments with generics for MlsProviderExtpubtraitMlsProviderExt:OpenMlsProvider{typeDbConnection;fnconn_ref(&self) -> &Self::DbConnection;}impl<C>MlsProviderExtforXmtpOpenMlsProviderPrivate<C>{typeDbConnection = DbConnectionPrivate<C>;fnconn_ref(&self) -> &Self::DbConnection{XmtpOpenMlsProviderPrivate::<C>::conn_ref(self)}}impl<T>MlsProviderExtfor&TwhereT:MlsProviderExt{typeDbConnection = <TasMlsProviderExt>::DbConnection;fnconn_ref(&self) -> &Self::DbConnection{T::conn_ref(&*self)}}impl<T>MlsProviderExtforArc<T>whereT:MlsProviderExt{typeDbConnection = <TasMlsProviderExt>::DbConnection;fnconn_ref(&self) -> &Self::DbConnection{T::conn_ref(&*self)}}
transaction, async_transaction and retryable_async_transaction could all be implemented on this trait as well.
The text was updated successfully, but these errors were encountered:
It's not sustainable to refactor provider into functions every couple months, and function duplication into
_with_provider
variants adds unnecessary noise. We should figure out a longer-term solution to share provider references without the churn.One possible solution:
XmtpOpenMlsProvider
, but holds aCow<_>
.ProviderRef<'_>
Option<Cow<Provider<'_>>
MlsGroup<'a, Client>
MlsGroup<'static, Client>
for the trivial case where it does not yet hold a provider, or the provider is owned. This should make it possible for all external functions to retain their same function signatures, without proliferating a lifetime everywhere in the codemls_provider()
method. Internally,ProviderRef
will check for the existence of a provider, and if it exists use the reference. Otherwise, it will pull a new providerPros:
&Provider
everywhere, or_with_provider
mls_provider()
Cons:
Solution that builds upon this:
we can encapsulate completely the provider management within
ProviderRef
and pull a new provider if needed withinOpenMlsProvider
implementation itself. Everywhere we currently accept a provider, we could acceptimpl OpenMlsProvider
or its genericfn<P: OpenMlsProvider>(provider: P)
variant. We additionally impement aProviderExt
trait that makes it possible to access Sqlite Connection from this, by appending an additional trait implementation:P: OpenMlsProvider + ProviderExt
.This may over-complicate in places for most things esp. with error type management in function callbacks, that would now have to specify something to the effect of
E: From<<P as OpenMlsProvider> as StorageProvider::Error>
which can become more complicated with further nested generics
Rough sketch of Provider Extension Trait
transaction
,async_transaction
andretryable_async_transaction
could all be implemented on this trait as well.The text was updated successfully, but these errors were encountered: