4 releases
Uses old Rust 2015
0.2.3 | Oct 11, 2019 |
---|---|
0.2.2 | Nov 6, 2018 |
0.2.1 | Nov 5, 2018 |
0.2.0 | Nov 5, 2018 |
#940 in Data structures
Used in degeneric-macros
25KB
224 lines
Galemu
galemu is a library to make it easy to work around not yet having generic associated types (GAT) wrt. lifetimes (GAL)
In current rust it can be tricky to abstract over some types due to not having generic associated types (GAT) in rust (yet). Often it is just necessary to have GAT wrt. liftimes and this crate provides some helpers to work around this.
Example Problem
For example you want to abstract over a (db) connection being able to open a transaction and that transaction being commitable. Once rust has GAT you would write following (stringly simplified, e.g. without returning results, additional methods etc.):
trait GenericConnection {
type Transaction<'conn>: GenericTransaction;
// the lifetime could have been omitted
fn create_transaction<'s>(&'s self) -> Self::Transaction<'s>;
}
trait GenericTransaction {
fn commit(self);
}
And then you could implement GenericTransaction
for any Transaction<'a>
.
But today you can only have following:
trait GenericConnection {
type Transaction: GenericTransaction;
// the lifetime could have been omitted
fn create_transaction(&self) -> Self::Transaction;
}
trait GenericTransaction {
fn commit(self);
}
But if you want to implement it for a Transaction<'conn>
you can't as
the 'conn
needs to be bound to the lifetime of the create_transaction
function.
Problem workaround
The idea of this crate is to lift the liftime into a know wraper type resulting in following setup:
use galemu::{Bound, BoundExt};
trait GenericConnection {
type Transaction: GenericTransaction;
// the lifetime could have been omitted
fn create_transaction<'s>(&'s self) -> Bound<'s, Self::Transaction>;
}
trait GenericTransaction: for<'a> BoundExt<'a> {
// on nightly use the "arbitrary self type" feature
fn commit(me: Bound<'s, Self>);
}
And for implementing it you would use following:
use galemu::{create_gal_wrapper_type};
create_gal_wrapper_type!{
/// Wraps `Transaction` erasing it's lifetime.
///
/// This can only be used through a `Bound<'a, TransactionWrapper>` instance,
/// as only then it is possible to access the wrapped type with the correct lifetime.
struct TransactionWrapper(Transaction<'a>);
}
impl GenericConnection for Connection {
type Transaction = TransactionWrapper;
fn create_transaction(&mut self) -> Bound<Self::Transaction> {
let trans = self.transaction();
TransactionWrapper::new(trans)
}
}
You can take a look at the module level documentation for a full example.