Expand description
§undoredo
undoredo is a Rust library that implements the Undo/Redo pattern on
arbitrary data structures by automatically recording sparse deltas (aka.
diffs, patches) of changes, or whole snapshots of past states (Memento
pattern).
This approach is much easier than the commonly used Command
pattern, which is the principle
of operation of other Undo/Redo crates, as having to implement commands requires
maintenance of additional application logic that is often complicated and can
lead to elusive bugs. But if needed, undoredo can also store a command or
other metadata along with every edit, allowing for easy use of the Command pattern
as well.
Delta-recording undo-redo requires creating a separate delta edit type for each
data structure. For ease of use, undoredo has derive macro
#[derive(Delta)]
to automatically generate these types on arbitrary custom structs and enums,
as well as convenience implementations for standard library collections:
HashMap,
HashSet,
BTreeMap,
BTreeSet,
Vec,
and for some third-party feature-gated types:
StableVec,
thunderdome::Arena,
rstar::RTree,
rstared::RTreed (read more in the
Supported containers section).
This library is compatible with no_std and serde and has no mandatory
third-party dependencies except for alloc.
§Demo

The above demo animation shows Undo/Redo action over dynamically added and subtracted polygons with R-tree spatial indexing. Neither commands nor snapshots are stored, but all edits in history are made of sparse deltas of the polygon container and the associated R-tree:
Source code with instructions for running the above interactive visualization can be found in the repository of the polygon_unionfind crate (see its README for details).
§Usage
§Adding dependency
First, add undoredo as a dependency to your Cargo.toml:
[dependencies]
undoredo = { version = "0.10.13", features = ["derive"] }The derive feature flag is only required when using deltas on custom struct
or enum types to derive delta edit types. Snapshots and commands work without
any derives.
§Usage examples
§Delta recorder over BTreeMap
Following is a basic usage example of delta-recording undo-redo over BTreeMap.
You can find more examples in the
examples/
directory.
use std::collections::BTreeMap;
use undoredo::{BTreeMapDelta, Recorder, UndoRedo};
fn main() {
// The recorder records the ongoing changes to the recorded container.
let mut recorder: Recorder<BTreeMap<usize, char>> =
Recorder::new(BTreeMap::new());
// The undo-redo struct that holds and maintains the undo-redo bistack.
let mut undoredo: UndoRedo<BTreeMapDelta<usize, char>> = UndoRedo::new();
// Push elements while recording the changes in a delta.
recorder.insert(1, 'A');
recorder.insert(2, 'B');
recorder.insert(3, 'C');
// The pushed elements are now present in the container.
assert!(*recorder.container() == BTreeMap::from([(1, 'A'), (2, 'B'), (3, 'C')]));
// Flush the recorder and commit the recorded delta of pushing 'A', 'B', 'C'
// into the undo-redo bistack.
undoredo.commit(&mut recorder);
// Now undo the action.
undoredo.undo(&mut recorder);
// The container is now empty; the action of pushing elements has been undone.
assert!(*recorder.container() == BTreeMap::from([]));
// Now redo the action.
undoredo.redo(&mut recorder);
// The elements are back in the container; the action has been redone.
assert!(*recorder.container() == BTreeMap::from([(1, 'A'), (2, 'B'), (3, 'C')]));
// Once you are done recording, you can dissolve the recorder to regain
// ownership and mutability over the recorded container.
let (btreemap, ..) = recorder.dissolve();
assert!(btreemap == BTreeMap::from([(1, 'A'), (2, 'B'), (3, 'C')]));
}§Delta recorder over custom struct or enum
A data structure may not be one of the supported containers, but it may be
a custom struct or enum, made of multiple containers or other members,
possibly with additional generics and fields that should not be subject to
undo-redo. To be able to perform delta recording in such case, you need to
implement a delta structure for it together with two operations,
.apply_delta()
and
.flush_delta().
This can usually be easily done automatically by just applying a provided derive
macro,
#[derive(Delta)]
.
Below is an example of an undoredoable
struct-of-arrays
storage with generic coordinate type K that could be used for a simple
entity-component-system:
// No need for `#[derive(Delta)]` for types stored in containers, only the
// containers themselves need this.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vector2<T> {
x: T,
y: T,
}
// `#[derive(Delta)]` generates the `EntitiesDelta` type, which is needed to
// store deltas as edits in an `UndoRedo` bistack.
#[derive(Delta)]
// You can choose the name for the generated delta edit type through the
// `undoredo` attribute with key `delta`. If you omit this, the default is
// the name of the input type followed by the word `Delta`. The name chosen in
// this example, `EntitiesDelta`, happens to be the same as the default.
#[undoredo(delta = EntitiesDelta)]
// Each delta is made of two collections of elements called "half-deltas".
// `#[derive(Delta)]` generates a type for them as well, named similarly to full
// deltas. If that name does not suit you, you can analogously use the
// `undoredo` attribute with key `half_delta` to rename them.,
#[undoredo(half_delta = EntitiesHalfDelta)]
pub struct Entities<T> {
positions: Recorder<Vec<Vector2<T>>>,
velocities: Recorder<Vec<Vector2<T>>>,
healths: Recorder<Vec<i64>>,
// You can record changes to primitive types too, not just collections.
turn_counter: Recorder<u64>,
// You can make fields not be subject to undo-redo by marking them with
// `#[undoredo(skip)]`.
// Note that this skipping only works for delta-based undo-redo because
// snapshots and commands rely on different mechanisms.
#[undoredo(skip)]
not_in_delta: String,
}See examples/entities.rs for the full example.
§Storing command metadata along with edits
It is often desirable to store some metadata along with every recorded edit,
usually some representation of the command that originated it. This can be done
by instead committing the edit using the
.cmd_commit()
method.
The bistack of done and undone committed edits, together with their command
metadatas (“cmd”) if present, can be accessed as slices from the
.done()
and
.undone()
accessor methods.
use std::collections::BTreeMap;
use undoredo::{BTreeMapDelta, Recorder, UndoRedo};
// Representation of the command that originated the recorded delta.
#[derive(Debug, Clone, PartialEq)]
enum Command {
PushChar,
}
fn main() {
let mut recorder: Recorder<BTreeMap<usize, char>> =
Recorder::new(BTreeMap::new());
let mut undoredo: UndoRedo<BTreeMapDelta<usize, char>, Command> = UndoRedo::new();
recorder.insert(1, 'A');
recorder.insert(2, 'B');
// Commit `Command::PushChar` enum variant as command metadata ("cmd") along
// with the recorded delta.
undoredo.cmd_commit(Command::PushChar, recorder.flush_delta());
// `Command::PushChar` is now the top element of the stack of done cmd-deltas.
assert_eq!(undoredo.done().last().unwrap().cmd, Command::PushChar);
undoredo.undo(&mut recorder);
// After undo, `Command::PushChar` is now the top element of the stack of
// undone cmd-deltas.
assert_eq!(undoredo.undone().last().unwrap().cmd, Command::PushChar);
}§Command pattern
You can also give up edits altogether and only store commands in the metadata field, thereby implementing the Command pattern. See examples/commands.rs for an example.
§Snapshot-based undo-redo
You can easily perform undo-redo using snapshots (that is, by storing whole past
states instead of only diffs between them) instead of deltas or commands. If you
were using deltas, you need to remove the
Recorder<...>
wrapper over your container and instead use the
Snapshot<...>
wrapper in place of the Delta<...> type.
For instance, if your container is HashMap<usize, char>, it will look like
this:
let mut container: HashMap<usize, char> = HashMap::new();
let mut undoredo: UndoRedo<Snapshot<HashMap<usize, char>>> = UndoRedo::new();This will work for all container types that implement Clone, without need
for any derive macro invocations or additional trait implementations as is with
deltas.
However, there are two caveats not present with deltas: if you want to be able to restore the container to its initial (often empty) state, you need to commit it first. And if you end up committing your latest changes, to revert them you will need to invoke undo twice, since the first undo just restores the state to the top of the undone stack.
For a full usage example, see examples/snapshots.rs.
§Delta recording on maps with pushing
Some containers with map semantics also provide a special type of insertion
where a value is inserted without specifying a key, which the container instead
automatically generates and returns by itself. In undoredo, this operation is
called pushing.
If a supported type has such a push interface, you can record its changes just
as easily as insertions and removals by calling
.push()
on the recorder, like this:
recorder.push('A');StableVec and thunderdome::Arena are instances of supported pushable maps.
See
examples/stable_vec.rs
and
examples/thunderdome.rs
for complete examples of their usage.
§Delta recording on sets
Some containers have set semantics: they operate only on values, without
exposing any usable notion of key or index. undoredo can provide delta-based
undo-redo functionality to such a set by treating it as a ()-valued map whose
keys are the set’s values. This is actually also how Rust’s standard library
internally
represents
its two set types, HashSet
and
BTreeSet.
As an example, the following code will construct a recorder and an undo-redo
bistack for a BTreeSet:
let mut recorder: Recorder<BTreeSet<char>> = Recorder::new(BTreeSet::new());
let mut undoredo: UndoRedo<Delta<BTreeSet<char>>> = UndoRedo::new();Keeping in mind to pass values as keys, recorder and
undoredo can then be used the same way as with maps above. See
examples/btreeset.rs
for a complete example.
Among the supported third-party types, rstar::RTree is one data structure for
which undoredo has a convenience implementation over set semantics. See
examples/rstar.rs
for an example of its usage.
NOTE: Some set-like data structures are actually multisets: they allow
to insert the same value multiple times without overriding the first one. In
fact, rstar::RTree is a multiset. undoredo will work correctly with such
data structures, seeing them as sets, but only if you never make use of their
multiset property: you must never insert a key again when it is already present
in a multiset.
§Supported containers
§When using snapshots
All data structures that implement the
Clone trait are
supported for snapshot-based undo-redo.
§When using commands
For command-based undo-redo, obviously all data structures are supported as long as the library user implements commands for them.
§When using deltas
To be able to use delta-based undo-redo on a data structure, it is necessary
to have a delta structure as well as two operations,
.apply_delta()
and
.flush_delta(),
available as traits. For ease of use, undoredo supplies a number of built-in
convenience implementations of all these for various commonly-used container
types.
For custom data structures, there is a derive macro, #[derive(Delta)], that
will generate all the necessary code.
Though we try our best, this derive macro may not work on some highly-generic data types. And in some cases, it may be desirable to add some additional logic to the operations. In these situations, it is necessary to implement the delta structure and operations on it manually.
For an example of a manual implementation, take a look at mikwielgus/polygon_unionfind/src/unionfind.rs. This is a delta-undoredoable union-find where every field’s type is a generic parameter.
§Standard library
Rust’s standard library maps and sets have built-in convenience implementations of delta-editing:
HashMap, gated by thestdfeature flag (enabled by default);HashSet, gated by thestdfeature flag (enabled by default);BTreeMap, not feature-gated;BTreeSet, not feature-gated;Vec, not feature-gated.
§Third-party types
In addition to the standard library, undoredo has also has built-in
feature-gated convenience implementations of delta-editing for data structures
from certain external crates:
stable_vec::StableVec, gated by thestable-vecfeature flag (usage example: examples/stable_vec.rs);thunderdome::Arena, gated by thethunderdomefeature flag (usage example: examples/thunderdome.rs);rstar::RTree, gated by therstarfeature flag (usage example: examples/rstar.rs);rstared::RTreed, gated by therstaredfeature flag (usage example: examples/rstared.rs).
To use these, enable their corresponding feature flags next to your undoredo
dependency in your Cargo.toml. For example, to enable all third-party type
implementations, write
[dependencies]
undoredo = { version = "0.10.13", features = ["stable-vec", "thunderdome", "rstar", "rstared"] }§Custom types
To make delta-based undo-redo work with a map-like non-composite
container data structure for which there is no convenience implementation,
you can create one on your own by implementing the traits from the
maplike crate. Refer to that crate’s
documentation for details. These traits are also re-exported by undoredo, so
it is not necessary to add another dependency.
If you believe that other people could benefit from your implementation,
consider contributing it to maplike. We will integrate it in undoredo on our
own afterwards (no need to open more than one pull request).
§Unsupported containers
Some containers cannot be supported for delta-based
undo-redo because they lack an interface on which
maplike’s traits could be implemented. See the Unsupported
containers
section in maplike’s documentation for details.
§Documentation
See the documentation for more information
on undoredo’s usage.
§Packaging
undoredo is published as a crate on the
Crates.io registry.
§Contributing
We welcome issues, pull requests and any other contributions from anyone to our repository on GitHub.
§Licence
§Outbound licence
undoredo is dual-licensed as under either of
at your option.
§Inbound licence
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work by you will be dual-licensed as described above, without any additional terms or conditions.
§Feature flags
derive— Enables theDeltaderive macro (and also its constituent macros,ApplyDelta,FlushDelta,HalfDelta).serde— Enablesserdesupport (derivesSerializeandDeserializetraits).std(enabled by default) — Disable forno_stdcompatibility.rstar— Enables support of delta-recording forrstar::RTreetype.rstared— Enables support of delta-recording forrstared::RTreedtype.stable-vec— Enables support of delta-recording forstable_vec::StableVectype.thunderdome— Enables support of delta-recording forthunderdome::Arenatype.
Re-exports§
pub extern crate alloc;
Structs§
- CmdEdit
- An edit along with metadata.
- Delta
- A reversible set of changes to a container.
- Recorder
- Records deltas applied to a container so that they can be replayed or reverted.
- Snapshot
- A snapshot of the whole state of a container.
- Undo
Redo - An undo-redo bistack.
Traits§
- Apply
Delta - Apply the changes in a delta to a container.
- Container
- Base trait for keyed collections, without any operations defined yet.
- Extract
- Extract an edit corresponding to the current state.
- Flush
Delta - Flush the recorder, returning the recorded delta and replacing it with a new empty one.
- Get
- Returns a reference to the value corresponding to the key.
- Insert
- Insert a new key-value pair into the collection at an arbitrary key.
- Into
Iter - Consume the collection and yield owned key-value pairs.
- Maplike
- A keyed collection with get, set, insert, remove, clear operations.
- Push
- Insert a value into the collection without specifying a key, returning the key that was automatically generated.
- Remove
- Remove an element under a key from the collection, returning the value at the key if the key was previously in the map. Other keys are not invalidated.
- Revert
- Revert an edit and return an edit that reverts the revert.
- Scalarlike
- A single assignable value.
- Setlike
- A map-like keyed collection whose value is the unit type, thus behaving like a set.
- Veclike
- An array-like keyed collection with additional push, pop, clear operations.
Type Aliases§
- BTree
MapDelta - Delta for
BTreeMap<K, V>. Alias forDelta<BTreeMapHalfDelta<K, V>>. - BTree
MapHalf Delta - Half-delta for
BTreeMap<K, V>. Alias forBTreeMap<K, V>. - BTree
SetDelta - Delta for
BTreeSet<K>. Alias forDelta<BTreeSetHalfDelta<K>>. - BTree
SetHalf Delta - Half-delta for
BTreeSet<K>. Alias forBTreeMap<K, ()>. - Bool
Delta - Delta for
bool. Alias forDelta<BoolHalfDelta>. - Bool
Half Delta - Half-delta for
bool. Alias forBTreeMap<usize, bool>. - Char
Delta - Delta for
char. Alias forDelta<CharHalfDelta>. - Char
Half Delta - Half-delta for
char. Alias forBTreeMap<usize, char>. - F32Delta
- Delta for
f32. Alias forDelta<F32HalfDelta>. - F32Half
Delta - Half-delta for
f32. Alias forBTreeMap<usize, f32>. - F64Delta
- Delta for
f64. Alias forDelta<F64HalfDelta>. - F64Half
Delta - Half-delta for
f64. Alias forBTreeMap<usize, f64>. - Hash
MapDelta std - Delta for
HashMap<K, V>. Alias forDelta<HashMapHalfDelta<K, V>>. - Hash
MapHalf Delta std - Half-delta for
HashMap<K, V>. Alias forHashMap<K, V>. - Hash
SetDelta std - Delta for
HashSet<K>. Alias forDelta<HashSetHalfDelta<K>>. - Hash
SetHalf Delta std - Half-delta for
HashSet<K>. Alias forHashMap<K, ()>. - I8Delta
- Delta for
i8. Alias forDelta<I8HalfDelta>. - I8Half
Delta - Half-delta for
i8. Alias forBTreeMap<usize, i8>. - I16Delta
- Delta for
i16. Alias forDelta<I16HalfDelta>. - I16Half
Delta - Half-delta for
i16. Alias forBTreeMap<usize, i16>. - I32Delta
- Delta for
i32. Alias forDelta<I32HalfDelta>. - I32Half
Delta - Half-delta for
i32. Alias forBTreeMap<usize, i32>. - I64Delta
- Delta for
i64. Alias forDelta<I64HalfDelta>. - I64Half
Delta - Half-delta for
i64. Alias forBTreeMap<usize, i64>. - I128
Delta - Delta for
i128. Alias forDelta<I128HalfDelta>. - I128
Half Delta - Half-delta for
i128. Alias forBTreeMap<usize, i128>. - Isize
Delta - Delta for
isize. Alias forDelta<IsizeHalfDelta>. - Isize
Half Delta - Half-delta for
isize. Alias forBTreeMap<usize, isize>. - Phantom
Data Delta - Delta for
PhantomData<V>. Alias forDelta<PhantomDataHalfDelta>. - Phantom
Data Half Delta - Half-delta for
PhantomData<V>. Alias forBTreeMap<usize, ()>. - RTree
Delta rstar - Delta for
RTree<K>. Alias forDelta<RTreeHalfDelta<K>>. - RTree
Half Delta rstar - Half-delta for
RTree<K>. Alias forBTreeMap<K, ()>. - RTreed
Delta rstared - Delta for
RTreed<C>. Alias forDelta<RTreedHalfDelta<K, V>>. - RTreed
Half Delta rstared - Half-delta for
RTreed<C>. Alias forBTreeMap<K, V>. - Stable
VecDelta stable-vec - Delta for
StableVecFacade<V, C>. Alias forDelta<StableVecHalfDelta<V>>. - Stable
VecHalf Delta stable-vec - Half-delta for
StableVecFacade<V, C>. Alias forBTreeMap<usize, V>. - Thunderdome
Delta thunderdome - Delta for
Arena<V>. Alias forDelta<ThunderdomeHalfDelta<V>>. - Thunderdome
Half Delta thunderdome - Half-delta for
Arena<V>. Alias forBTreeMap<Index, V>. - Tuple1
Delta - Delta for
(T0, ). Alias forDelta<Tuple1HalfDelta<T0, >>. - Tuple1
Half Delta - Half-delta for
(T0, ). Alias forBTreeMap<usize, (T0, )>. - Tuple2
Delta - Delta for
(T0, T1, ). Alias forDelta<Tuple2HalfDelta<T0, T1, >>. - Tuple2
Half Delta - Half-delta for
(T0, T1, ). Alias forBTreeMap<usize, (T0, T1, )>. - Tuple3
Delta - Delta for
(T0, T1, T2, ). Alias forDelta<Tuple3HalfDelta<T0, T1, T2, >>. - Tuple3
Half Delta - Half-delta for
(T0, T1, T2, ). Alias forBTreeMap<usize, (T0, T1, T2, )>. - Tuple4
Delta - Delta for
(T0, T1, T2, T3, ). Alias forDelta<Tuple4HalfDelta<T0, T1, T2, T3, >>. - Tuple4
Half Delta - Half-delta for
(T0, T1, T2, T3, ). Alias forBTreeMap<usize, (T0, T1, T2, T3, )>. - Tuple5
Delta - Delta for
(T0, T1, T2, T3, T4, ). Alias forDelta<Tuple5HalfDelta<T0, T1, T2, T3, T4, >>. - Tuple5
Half Delta - Half-delta for
(T0, T1, T2, T3, T4, ). Alias forBTreeMap<usize, (T0, T1, T2, T3, T4, )>. - Tuple6
Delta - Delta for
(T0, T1, T2, T3, T4, T5, ). Alias forDelta<Tuple6HalfDelta<T0, T1, T2, T3, T4, T5, >>. - Tuple6
Half Delta - Half-delta for
(T0, T1, T2, T3, T4, T5, ). Alias forBTreeMap<usize, (T0, T1, T2, T3, T4, T5, )>. - Tuple7
Delta - Delta for
(T0, T1, T2, T3, T4, T5, T6, ). Alias forDelta<Tuple7HalfDelta<T0, T1, T2, T3, T4, T5, T6, >>. - Tuple7
Half Delta - Half-delta for
(T0, T1, T2, T3, T4, T5, T6, ). Alias forBTreeMap<usize, (T0, T1, T2, T3, T4, T5, T6, )>. - Tuple8
Delta - Delta for
(T0, T1, T2, T3, T4, T5, T6, T7, ). Alias forDelta<Tuple8HalfDelta<T0, T1, T2, T3, T4, T5, T6, T7, >>. - Tuple8
Half Delta - Half-delta for
(T0, T1, T2, T3, T4, T5, T6, T7, ). Alias forBTreeMap<usize, (T0, T1, T2, T3, T4, T5, T6, T7, )>. - Tuple9
Delta - Delta for
(T0, T1, T2, T3, T4, T5, T6, T7, T8, ). Alias forDelta<Tuple9HalfDelta<T0, T1, T2, T3, T4, T5, T6, T7, T8, >>. - Tuple9
Half Delta - Half-delta for
(T0, T1, T2, T3, T4, T5, T6, T7, T8, ). Alias forBTreeMap<usize, (T0, T1, T2, T3, T4, T5, T6, T7, T8, )>. - Tuple10
Delta - Delta for
(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, ). Alias forDelta<Tuple10HalfDelta<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, >>. - Tuple10
Half Delta - Half-delta for
(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, ). Alias forBTreeMap<usize, (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, )>. - Tuple11
Delta - Delta for
(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, ). Alias forDelta<Tuple11HalfDelta<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, >>. - Tuple11
Half Delta - Half-delta for
(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, ). Alias forBTreeMap<usize, (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, )>. - Tuple12
Delta - Delta for
(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, ). Alias forDelta<Tuple12HalfDelta<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, >>. - Tuple12
Half Delta - Half-delta for
(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, ). Alias forBTreeMap<usize, (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, )>. - U8Delta
- Delta for
u8. Alias forDelta<U8HalfDelta>. - U8Half
Delta - Half-delta for
u8. Alias forBTreeMap<usize, u8>. - U16Delta
- Delta for
u16. Alias forDelta<U16HalfDelta>. - U16Half
Delta - Half-delta for
u16. Alias forBTreeMap<usize, u16>. - U32Delta
- Delta for
u32. Alias forDelta<U32HalfDelta>. - U32Half
Delta - Half-delta for
u32. Alias forBTreeMap<usize, u32>. - U64Delta
- Delta for
u64. Alias forDelta<U64HalfDelta>. - U64Half
Delta - Half-delta for
u64. Alias forBTreeMap<usize, u64>. - U128
Delta - Delta for
u128. Alias forDelta<U128HalfDelta>. - U128
Half Delta - Half-delta for
u128. Alias forBTreeMap<usize, u128>. - Unit
Delta - Delta for
(). Alias forDelta<UnitHalfDelta>. - Unit
Half Delta - Half-delta for
(). Alias forBTreeMap<usize, ()>. - Usize
Delta - Delta for
usize. Alias forDelta<UsizeHalfDelta>. - Usize
Half Delta - Half-delta for
usize. Alias forBTreeMap<usize, usize>. - VecDelta
- Delta for
Vec<V>. Alias forDelta<VecHalfDelta<V>>. - VecHalf
Delta - Half-delta for
Vec<V>. Alias forBTreeMap<usize, V>.
Derive Macros§
- Apply
Delta derive - Generates an impl of the trait
ApplyDelta. - Container
- Delta
derive - Generates an impl of the trait
ApplyDelta. - Flush
Delta derive - Generates an impl of the trait
FlushDelta. - Half
Delta derive - Generates a half-delta type for the given
structorenum.