{"id":50897854,"url":"https://github.com/mikwielgus/undoredo","last_synced_at":"2026-07-15T16:01:33.998Z","repository":{"id":329169663,"uuid":"1115805602","full_name":"mikwielgus/undoredo","owner":"mikwielgus","description":"Undo/Redo in Rust using deltas, snapshots or commands with convenience implementations for many standard and third-party types.","archived":false,"fork":false,"pushed_at":"2026-07-10T11:07:00.000Z","size":2126,"stargazers_count":118,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"develop","last_synced_at":"2026-07-10T12:13:13.488Z","etag":null,"topics":["gui","redo","rust","undo","undo-redo"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/undoredo","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mikwielgus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yaml","license":"LICENSES/Apache-2.0.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"mikwielgus"}},"created_at":"2025-12-13T15:37:10.000Z","updated_at":"2026-07-10T11:07:25.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mikwielgus/undoredo","commit_stats":null,"previous_names":["mikwielgus/undoredo"],"tags_count":88,"template":false,"template_full_name":null,"purl":"pkg:github/mikwielgus/undoredo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikwielgus%2Fundoredo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikwielgus%2Fundoredo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikwielgus%2Fundoredo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikwielgus%2Fundoredo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikwielgus","download_url":"https://codeload.github.com/mikwielgus/undoredo/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikwielgus%2Fundoredo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35511400,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-15T02:00:06.706Z","response_time":131,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gui","redo","rust","undo","undo-redo"],"created_at":"2026-06-16T01:31:30.083Z","updated_at":"2026-07-15T16:01:33.966Z","avatar_url":"https://github.com/mikwielgus.png","language":"Rust","funding_links":["https://github.com/sponsors/mikwielgus"],"categories":["gui","Libraries"],"sub_categories":["Data structures"],"readme":"\u003c!--\nSPDX-FileCopyrightText: 2025 undoredo contributors\n\nSPDX-License-Identifier: MIT OR Apache-2.0\n--\u003e\n\n[![Docs](https://docs.rs/undoredo/badge.svg)](https://docs.rs/undoredo/)\n[![Crates.io](https://img.shields.io/crates/v/undoredo.svg)](https://crates.io/crates/undoredo)\n[![MIT OR Apache 2.0](https://img.shields.io/crates/l/undoredo.svg)](#licence)\n\n# undoredo\n\n`undoredo` is a Rust library that implements the Undo/Redo pattern on\narbitrary data structures by automatically recording sparse *deltas* (aka.\n*diffs*, *patches*) of changes, or whole *snapshots* of past states ([Memento\npattern](https://en.wikipedia.org/wiki/Memento_pattern)). These edits can then\nbe stored in linear undo-redo bistack or non-linear history tree provided by\nthe library.\n\nThis approach is much easier than the commonly used [Command\npattern](https://en.wikipedia.org/wiki/Command_pattern), which is the principle\nof operation of other Undo/Redo crates, as having to implement commands requires\nmaintenance of additional application logic that is often complicated and can\nlead to elusive bugs. But if needed, `undoredo` can also store a command or\nother metadata along with every edit, allowing for easy use of the Command pattern\nas well.\n\nDelta-recording undo-redo requires creating a separate delta edit type for each\ndata structure. For ease of use, `undoredo` has derive macro\n[`#[derive(Delta)]`](https://docs.rs/undoredo/latest/undoredo/derive.Delta.html)\nto automatically generate these types on arbitrary custom `struct`s and `enum`s.\nThere are also convenience implementations for standard library collections:\n[`HashMap`](https://doc.rust-lang.org/std/collections/struct.HashMap.html),\n[`HashSet`](https://doc.rust-lang.org/std/collections/struct.HashSet.html),\n[`BTreeMap`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html),\n[`BTreeSet`](https://doc.rust-lang.org/std/collections/struct.BTreeSet.html),\n[`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html),\nand for some third-party feature-gated types:\n[`bidimap::BiBTreeMap` and `bidimap::BiHashMap`](https://docs.rs/bidimap/latest/bidimap/),\n[`rstar::RTree`](https://docs.rs/rstar/0.12.2/rstar/struct.RTree.html),\n[`rstared::RTreed`](https://docs.rs/rstared/latest/rstared/),\n[`StableVec`](https://docs.rs/stable-vec/latest/stable_vec/type.StableVec.html),\n[`thunderdome::Arena`](https://docs.rs/thunderdome/latest/thunderdome/),\n(read more in the [Supported containers](#supported-containers) section).\n\nThis library is compatible with `no_std` and `serde` and has no mandatory\nthird-party dependencies except for [`alloc`](https://doc.rust-lang.org/alloc/).\n\n## Demo\n\n![Animation showing polygons being added and subtracted in the demo stored in\n`demos/polygon_set/` directory of the repository of the polygon_unionfind crate.\n](https://raw.githubusercontent.com/mikwielgus/undoredo/refs/heads/develop/polygon_set_demo.gif)\n\nThe above demo animation shows Undo/Redo action over dynamically added and\nsubtracted polygons with R-tree spatial indexing. Neither commands nor snapshots\nare stored, but all edits in history are made of sparse deltas of the polygon\ncontainer and the associated R-tree.\n\nSource code with instructions for running the above interactive visualization\ncan be found in the repository of the\n[polygon_unionfind](https://github.com/mikwielgus/polygon_unionfind) crate (see\nits README for details).\n\n## Usage\n\n### Adding dependency\n\nFirst, add `undoredo` as a dependency to your `Cargo.toml`:\n\n```toml\n[dependencies]\nundoredo = { version = \"0.12.0\", features = [\"derive\"] }\n```\n\nThe `derive` feature flag is only required when using deltas on custom `struct`\nor `enum` types to derive delta edit types. Snapshots and commands work without\nany derives.\n\n### Usage examples\n\n#### Delta recorder over `BTreeMap`\n\nFollowing is a basic usage example of delta-recording undo-redo over `BTreeMap`.\nYou can find more examples in the\n[examples/](https://github.com/mikwielgus/undoredo/tree/develop/examples)\ndirectory.\n\n```rust\nuse std::collections::BTreeMap;\nuse undoredo::aliases::BTreeMapDelta;\nuse undoredo::{Recorder, UndoRedo};\n\nfn main() {\n    // The recorder records the ongoing changes to the recorded container.\n    let mut recorder: Recorder\u003cBTreeMap\u003cusize, char\u003e\u003e =\n        Recorder::new(BTreeMap::new());\n\n    // The undo-redo struct that holds and maintains the undo-redo bistack.\n    let mut undoredo: UndoRedo\u003cBTreeMapDelta\u003cusize, char\u003e\u003e = UndoRedo::new();\n\n    // Push elements while recording the changes in a delta.\n    recorder.insert(1, 'A');\n    recorder.insert(2, 'B');\n    recorder.insert(3, 'C');\n\n    // The pushed elements are now present in the container.\n    assert!(*recorder.container() == BTreeMap::from([(1, 'A'), (2, 'B'), (3, 'C')]));\n\n    // Flush the recorder and commit the recorded delta of pushing 'A', 'B', 'C'\n    // into the undo-redo bistack.\n    undoredo.commit(\u0026mut recorder);\n\n    // Now undo the action.\n    undoredo.undo(\u0026mut recorder);\n\n    // The container is now empty; the action of pushing elements has been undone.\n    assert!(*recorder.container() == BTreeMap::from([]));\n\n    // Now redo the action.\n    undoredo.redo(\u0026mut recorder);\n\n    // The elements are back in the container; the action has been redone.\n    assert!(*recorder.container() == BTreeMap::from([(1, 'A'), (2, 'B'), (3, 'C')]));\n\n    // Once you are done recording, you can dissolve the recorder to regain\n    // ownership and mutability over the recorded container.\n    let (btreemap, ..) = recorder.dissolve();\n    assert!(btreemap == BTreeMap::from([(1, 'A'), (2, 'B'), (3, 'C')]));\n}\n```\n\n#### Delta recorder over custom `struct` or `enum`\n\nA data structure may not be one of the supported containers, but it may be\na custom `struct` or `enum`, made of multiple containers or other members,\npossibly with additional generics and fields that should not be subject to\nundo-redo. To be able to perform delta recording in such case, you need to\nimplement a delta structure for it together with two operations,\n[`.apply_delta()`](https://docs.rs/undoredo/latest/undoredo/delta/trait.ApplyDelta.html#tymethod.apply_delta)\nand\n[`.flush_delta()`](https://docs.rs/undoredo/latest/undoredo/trait.FlushDelta.html#tymethod.flush_delta).\nThis can usually be easily done automatically by just applying a provided derive\nmacro,\n[`#[derive(Delta)]`](https://docs.rs/undoredo/latest/undoredo/derive.Delta.html)\n.\n\nBelow is an example of an undoredoable\n[struct-of-arrays](https://en.wikipedia.org/wiki/AoS_and_SoA)\nstorage with generic coordinate type `T` that could be used for a simple\n[entity-component-system](https://en.wikipedia.org/wiki/Entity_component_system):\n\n```rust,ignore\n// No need for `#[derive(Delta)]` for types stored in containers, only the\n// containers themselves need this.\n#[derive(Clone, Copy, Debug, PartialEq)]\npub struct Vector2\u003cT\u003e {\n    x: T,\n    y: T,\n}\n\n// `#[derive(Delta)]` generates the `EntitiesDelta` type, which is needed to\n// store deltas as edits in an `UndoRedo` bistack.\n#[derive(Delta)]\n// You can choose the name for the generated delta edit type through the\n// `undoredo` attribute with key `delta`. If you omit this, the default is\n// the name of the input type followed by the word `Delta`. The name chosen in\n// this example, `EntitiesDelta`, happens to be the same as the default.\n#[undoredo(delta = EntitiesDelta)]\n// Each delta is made of two collections of elements called \"half-deltas\".\n// `#[derive(Delta)]` generates a type for them as well, named similarly to full\n// deltas. If that name does not suit you, you can analogously use the\n// `undoredo` attribute with key `half_delta` to rename them.\n#[undoredo(half_delta = EntitiesHalfDelta)]\npub struct Entities\u003cT\u003e {\n    positions: Recorder\u003cVec\u003cVector2\u003cT\u003e\u003e\u003e,\n    velocities: Recorder\u003cVec\u003cVector2\u003cT\u003e\u003e\u003e,\n    healths: Recorder\u003cVec\u003ci64\u003e\u003e,\n    // You can record changes to primitive types too, not just collections.\n    turn_counter: Recorder\u003cu64\u003e,\n    // You can make fields not be subject to undo-redo by marking them with\n    // `#[undoredo(skip)]`.\n    // Note that this skipping only works for delta-based undo-redo because\n    // snapshots and commands rely on different mechanisms.\n    #[undoredo(skip)]\n    not_in_delta: String,\n}\n```\n\nSee\n[examples/entities.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/entities.rs)\nfor the full example.\n\n#### Storing command metadata along with edits\n\nIt is often desirable to store some metadata along with every recorded edit,\nusually some representation of the command that originated it. This can be done\nby instead committing the edit using the\n[`.cmd_commit()`](https://docs.rs/undoredo/latest/undoredo/struct.UndoRedo.html#method.cmd_commit)\nmethod.\n\nThe bistack of done and undone committed edits, together with their command\nmetadatas (\"cmd\") if present, can be accessed as slices from the\n[`.done()`](https://docs.rs/undoredo/latest/undoredo/struct.UndoRedo.html#method.done)\nand\n[`.undone()`](https://docs.rs/undoredo/latest/undoredo/struct.UndoRedo.html#method.undone)\naccessor methods.\n\n```rust\nuse std::collections::BTreeMap;\nuse undoredo::aliases::BTreeMapDelta;\nuse undoredo::{Recorder, UndoRedo};\n\n// Representation of the command that originated the recorded delta.\n#[derive(Debug, Clone, PartialEq)]\nenum Command {\n    PushChar,\n}\n\nfn main() {\n    let mut recorder: Recorder\u003cBTreeMap\u003cusize, char\u003e\u003e =\n        Recorder::new(BTreeMap::new());\n    let mut undoredo: UndoRedo\u003cBTreeMapDelta\u003cusize, char\u003e, Command\u003e = UndoRedo::new();\n\n    recorder.insert(1, 'A');\n    recorder.insert(2, 'B');\n\n    // Commit `Command::PushChar` enum variant as command metadata (\"cmd\") along\n    // with the recorded delta.\n    undoredo.cmd_commit(Command::PushChar, \u0026mut recorder);\n\n    // `Command::PushChar` is now the top element of the stack of done cmd-deltas.\n    assert_eq!(undoredo.done().last().unwrap().cmd, Command::PushChar);\n\n    undoredo.undo(\u0026mut recorder);\n\n    // After undo, `Command::PushChar` is now the top element of the stack of\n    // undone cmd-deltas.\n    assert_eq!(undoredo.undone().last().unwrap().cmd, Command::PushChar);\n}\n```\n\n#### Command pattern\n\nYou can also give up edits altogether and only store commands in the metadata\nfield, thereby implementing the Command pattern. See\n[examples/commands.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/commands.rs)\nfor an example.\n\n#### Snapshot-based undo-redo\n\nYou can easily perform undo-redo using snapshots (that is, by storing whole past\nstates instead of only diffs between them) instead of deltas or commands. If you\nwere using deltas, you need to remove the\n[`Recorder\u003c...\u003e`](https://docs.rs/undoredo/latest/undoredo/struct.Recorder.html)\nwrapper over your container and instead use the\n[`Snapshot\u003c...\u003e`](https://docs.rs/undoredo/latest/undoredo/struct.Snapshot.html)\nwrapper in place of the `Delta\u003c...\u003e` type.\n\nFor instance, if your container is `HashMap\u003cusize, char\u003e`, it will look like\nthis:\n\n```rust,ignore\nlet mut container: HashMap\u003cusize, char\u003e = HashMap::new();\nlet mut undoredo: UndoRedo\u003cSnapshot\u003cHashMap\u003cusize, char\u003e\u003e\u003e = UndoRedo::new();\n```\n\nThis will work for all container types that implement `Clone`, without need\nfor any derive macro invocations or additional trait implementations as is with\ndeltas.\n\nHowever, there are two caveats not present with deltas: if you want to be able\nto restore the container to its initial (often empty) state, you need to commit\nit first. And if you end up committing your latest changes, to revert them you\nwill need to invoke undo twice, since the first undo just restores the state to\nthe top of the *undone* stack.\n\nFor a full usage example, see\n[examples/snapshots.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/snapshots.rs).\n\n#### Delta-recording on maps with pushing\n\nSome containers with map semantics also provide a special type of insertion\nwhere a value is inserted without specifying a key, which the container instead\nautomatically generates and returns by itself. In `undoredo`, this operation is\ncalled *pushing*.\n\nIf a supported type has such a push interface, you can record its changes just\nas easily as insertions and removals by calling\n[`.push()`](https://docs.rs/undoredo/latest/undoredo/struct.Recorder.html#impl-Push%3CK%3E-for-Recorder%3CK,+V,+C,+DC%3E)\non the recorder, like this:\n\n```rust,ignore\nrecorder.push('A');\n```\n\n`StableVec` and `thunderdome::Arena` are instances of supported pushable maps.\nSee\n[examples/stable_vec.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/stable_vec.rs)\nand\n[examples/thunderdome.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/thunderdome.rs)\nfor complete examples of their usage.\n\n#### Delta-recording on sets\n\nSome containers have set semantics: they operate only on values, without\nexposing any usable notion of key or index. `undoredo` can provide delta-based\nundo-redo functionality to such a set by treating it as a `()`-valued map whose\nkeys are the set's values. This is actually also how Rust's standard library\ninternally\n[represents](https://docs.rs/hashbrown/latest/src/hashbrown/set.rs.html#115)\nits two set types, `HashSet`\n[and](https://doc.rust-lang.org/stable/src/alloc/collections/btree/set.rs.html)\n`BTreeSet`.\n\nAs an example, the following code will construct a recorder and an undo-redo\nbistack for a `BTreeSet`:\n\n```rust,ignore\nlet mut recorder: Recorder\u003cBTreeSet\u003cchar\u003e\u003e = Recorder::new(BTreeSet::new());\nlet mut undoredo: UndoRedo\u003cBTreeSetDelta\u003cchar\u003e\u003e = UndoRedo::new();\n```\n\nKeeping in mind to pass values as keys, `recorder` and\n`undoredo` can then be used the same way as with maps above. See\n[examples/btreeset.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/btreeset.rs)\nfor a complete example.\n\nAmong the supported third-party types, `rstar::RTree` is a data structure for\nwhich `undoredo` has a convenience implementation over set semantics. See\n[examples/rstar.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/rstar.rs)\nfor an example of its usage.\n\n**NOTE:** Some set-like data structures are actually multisets: they allow\nto insert the same value multiple times without overriding the first one. In\nfact, `rstar::RTree` is a multiset. `undoredo` will work correctly with such\ndata structures, seeing them as sets, but only if you never make use of their\nmultiset property: you must never insert a key again when it is already present\nin a multiset.\n\n#### Delta-recording on bidirectional maps\n\nDelta-recording can be performed on bidirectional maps (bimaps). `undoredo` has\na convenience implementation for `BiBTreeMap` and `BiHashMap` from the `bidimap`\ncrate (`bidimap` is a maintained fork of the `bimap` crate).\n\nSee\n[examples/bihashmap.rs](https://github.com/mikwielgus/undoredo/tree/develop/examples/bihashmap.rs)\nfor an example of undo-redo performed on a bidirectional map.\n\n## Supported containers\n\n### When using snapshots\n\nAll data structures that implement the\n[`Clone`](https://doc.rust-lang.org/std/clone/trait.Clone.html) trait are\nsupported for snapshot-based undo-redo.\n\n### When using commands\n\nFor command-based undo-redo, obviously all data structures are supported as long\nas the library user implements commands for them.\n\n### When using deltas\n\nTo be able to use delta-based undo-redo on a data structure, it is necessary\nto have a delta structure as well as two operations,\n[`.apply_delta()`](https://docs.rs/undoredo/latest/undoredo/delta/trait.ApplyDelta.html#tymethod.apply_delta)\nand\n[`.flush_delta()`](https://docs.rs/undoredo/latest/undoredo/trait.FlushDelta.html#tymethod.flush_delta),\navailable as traits. For ease of use, `undoredo` supplies a number of built-in\nconvenience implementations of all these for various commonly-used container\ntypes.\n\nFor custom data structures, there is a derive macro, `#[derive(Delta)]`, that\nwill generate all the necessary code.\n\nThough we try our best, this derive macro may not work on some highly-generic\ndata types. And in some cases, it may be desirable to add some additional logic\nto the operations. In these situations, it is necessary to implement the delta\nstructure and operations on it manually.\n\nFor an example of a manual implementation, take a look at\n[mikwielgus/polygon_unionfind/src/unionfind.rs](https://github.com/mikwielgus/polygon_unionfind/blob/develop/src/unionfind.rs#L141).\nThis is a delta-undoredoable union-find where every field's type is a generic\nparameter.\n\n#### Standard library\n\nRust's standard library maps and sets have built-in convenience implementations\nof delta-editing:\n\n- [`HashMap`](https://doc.rust-lang.org/std/collections/struct.HashMap.html), gated by the `std` feature flag (enabled by default);\n- [`HashSet`](https://doc.rust-lang.org/std/collections/struct.HashSet.html), gated by the `std` feature flag (enabled by default);\n- [`BTreeMap`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html), not feature-gated;\n- [`BTreeSet`](https://doc.rust-lang.org/std/collections/struct.BTreeSet.html), not feature-gated;\n- [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html), not feature-gated.\n\n#### Third-party types\n\nIn addition to the standard library, `undoredo` also has built-in feature-gated\nconvenience implementations of delta-editing for data structures from certain\nexternal crates:\n\n- [`bidimap::BiBTreeMap` and `bidimap::BiHashMap`](https://docs.rs/bidimap/latest/bidimap/),\n  gated by the `bidimap` feature flag (usage example:\n  [examples/bihashmap.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/bihashmap.rs));\n- [`rstar::RTree`](https://docs.rs/rstar/0.12.2/rstar/index.html), gated by the\n  `rstar` feature flag (usage example: [examples/rstar.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/rstar.rs));\n- [`rstared::RTreed`](https://docs.rs/rstared/latest/rstared/), gated by the\n  `rstared` feature flag (usage example: [examples/rstared.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/rstared.rs));\n- [`stable_vec::StableVec`](https://docs.rs/stable-vec/latest/stable_vec/),\n  gated by the `stable-vec` feature flag (usage example:\n  [examples/stable_vec.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/stable_vec.rs));\n- [`thunderdome::Arena`](https://docs.rs/thunderdome/latest/thunderdome/),\n  gated by the `thunderdome` feature flag (usage example:\n  [examples/thunderdome.rs](https://github.com/mikwielgus/undoredo/blob/develop/examples/thunderdome.rs)).\n\nTo use these, enable their corresponding feature flags next to your `undoredo`\ndependency in your `Cargo.toml`. For example, to enable all third-party type\nimplementations, write\n\n```toml\n[dependencies]\nundoredo = { version = \"0.12.0\", features = [\"bidimap\", \"rstar\", \"rstared\", \"stable-vec\", \"thunderdome\"] }\n```\n\n#### Custom types\n\nTo make delta-based undo-redo work with a map-like non-composite\ncontainer data structure for which there is no convenience implementation,\nyou can create one on your own by implementing the traits from the\n[maplike](https://crates.io/crates/maplike) crate. Refer to that crate's\ndocumentation for details. These traits are also re-exported by `undoredo`, so\nit is not necessary to add another dependency.\n\nIf you believe that other people could benefit from your implementation,\nconsider contributing it to `maplike`. We will integrate it in `undoredo` on our\nown afterwards (no need to open more than one pull request).\n\n#### Unsupported containers\n\nSome containers cannot be supported for delta-based\nundo-redo because they lack an interface on which\n`maplike`'s traits could be implemented. See the [Unsupported\ncontainers](https://docs.rs/maplike/latest/maplike/#unsupported-containers)\nsection in `maplike`'s documentation for details.\n\n## Documentation\n\nSee the [documentation](https://docs.rs/undoredo/latest/undoredo) for more information\non `undoredo`'s usage.\n\n## Packaging\n\n`undoredo` is published as a [crate](https://crates.io/crates/undoredo) on the\n[Crates.io](https://crates.io/) registry.\n\n## Contributing\n\nWe welcome issues, pull requests and any other contributions from anyone to our\n[repository](https://github.com/mikwielgus/undoredo) on GitHub.\n\n## Licence\n\n### Outbound licence\n\n`undoredo` is dual-licensed as under either of\n\n- [MIT license](./LICENSES/MIT.txt),\n- [Apache License, Version 2.0](./LICENSES/Apache-2.0.txt),\n\nat your option.\n\n### Inbound licence\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in this work by you will be dual-licensed as described above,\nwithout any additional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikwielgus%2Fundoredo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikwielgus%2Fundoredo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikwielgus%2Fundoredo/lists"}