I have a transaction system based on revertable operations. Each operation, in addition to its primary function, produces an UndoLog that knows how to back out the change that was made:
trait UndoLog<T> {
fn revert(self, _:&mut T);
}
Semantically, this should be a consuming function: Once an operation has been reverted, attempting to revert it again is an error. I have also defined several combinators that can compose UndoLogs:
() is a no-op log
(A,B) reverts A and then B
Vec<T> reverts each T in reverse order
Option<T> and Either<A,B> revert whichever variant is present
The transaction object holds an exclusive reference to the object being modified and uses these combinators to maintain an overall undo log. Because the type of the undo log changes with every operation, the type of the transaction object itself also changes with every operation.
In most cases this is fine, but sometimes it would be useful to have a unified type for the UndoLogs (and therefore the transactions that hold them). For example, it’s not feasible in my current setup to have a vector of transactions and apply an operation to just one of them.
To make this possible, I’d like to add a type-erasing combinator to the list above. It will obviously need to Box the UndoLog or otherwise store it on the heap. I can’t use Box<dyn UndoLog<T>>, though, because UndoLog isn’t object safe. I don’t want to change the function signature to self: Box<Self> because that would force lots of unnecessary heap allocations.
There is some precedent for this: FnOnce manages to be callable via a Box despite taking an owned self parameter, but I suspect it has special compiler support.
can work for you, too. (The UndoLogImpl trait would be just to simplify trait implementation, since you don’t have to provide a separate revert_boxed implementation this way. Unfortunately there is no other way to provide a default implementation without specialization AFAICT.)
I’m pleasantly surprised that doesn’t throw the trait solver into an infinite loop. I never would have thought of writing a blanket impl for the supertrait conditioned on the subtrait.