automerge-rb 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +175 -0
- data/ext/automerge_ext/automerge_ext.c +1805 -0
- data/ext/automerge_ext/extconf.rb +132 -0
- data/lib/automerge/version.rb +6 -0
- data/lib/automerge.rb +110 -0
- data/rust-toolchain.toml +4 -0
- data/vendor/automerge-rust/Cargo.lock +1909 -0
- data/vendor/automerge-rust/Cargo.toml +15 -0
- data/vendor/automerge-rust/automerge/Cargo.toml +78 -0
- data/vendor/automerge-rust/automerge/README.md +5 -0
- data/vendor/automerge-rust/automerge/benches/load_save.rs +102 -0
- data/vendor/automerge-rust/automerge/benches/map.rs +260 -0
- data/vendor/automerge-rust/automerge/benches/range.rs +37 -0
- data/vendor/automerge-rust/automerge/benches/sync.rs +95 -0
- data/vendor/automerge-rust/automerge/examples/README.md +7 -0
- data/vendor/automerge-rust/automerge/examples/quickstart.rs +57 -0
- data/vendor/automerge-rust/automerge/examples/watch.rs +94 -0
- data/vendor/automerge-rust/automerge/fuzz/Cargo.toml +29 -0
- data/vendor/automerge-rust/automerge/fuzz/fuzz_targets/load.rs +37 -0
- data/vendor/automerge-rust/automerge/src/autocommit.rs +1286 -0
- data/vendor/automerge-rust/automerge/src/automerge/current_state.rs +546 -0
- data/vendor/automerge-rust/automerge/src/automerge/tests.rs +2023 -0
- data/vendor/automerge-rust/automerge/src/automerge.rs +2071 -0
- data/vendor/automerge-rust/automerge/src/autoserde.rs +128 -0
- data/vendor/automerge-rust/automerge/src/change.rs +357 -0
- data/vendor/automerge-rust/automerge/src/change_graph.rs +1215 -0
- data/vendor/automerge-rust/automerge/src/change_queue.rs +46 -0
- data/vendor/automerge-rust/automerge/src/clock.rs +206 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range/boolean.rs +83 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range/delta.rs +148 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range/generic/group.rs +138 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range/generic/simple.rs +76 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range/generic.rs +93 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range/key.rs +272 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range/obj_id.rs +202 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range/opid_list.rs +329 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range/raw.rs +38 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range/rle.rs +216 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range/value.rs +547 -0
- data/vendor/automerge-rust/automerge/src/columnar/column_range.rs +17 -0
- data/vendor/automerge-rust/automerge/src/columnar/encoding/boolean.rs +197 -0
- data/vendor/automerge-rust/automerge/src/columnar/encoding/col_error.rs +88 -0
- data/vendor/automerge-rust/automerge/src/columnar/encoding/column_decoder.rs +133 -0
- data/vendor/automerge-rust/automerge/src/columnar/encoding/decodable_impls.rs +175 -0
- data/vendor/automerge-rust/automerge/src/columnar/encoding/delta.rs +96 -0
- data/vendor/automerge-rust/automerge/src/columnar/encoding/encodable_impls.rs +200 -0
- data/vendor/automerge-rust/automerge/src/columnar/encoding/leb128.rs +82 -0
- data/vendor/automerge-rust/automerge/src/columnar/encoding/properties.rs +178 -0
- data/vendor/automerge-rust/automerge/src/columnar/encoding/raw.rs +101 -0
- data/vendor/automerge-rust/automerge/src/columnar/encoding/rle.rs +239 -0
- data/vendor/automerge-rust/automerge/src/columnar/encoding.rs +67 -0
- data/vendor/automerge-rust/automerge/src/columnar/splice_error.rs +47 -0
- data/vendor/automerge-rust/automerge/src/columnar.rs +14 -0
- data/vendor/automerge-rust/automerge/src/convert.rs +112 -0
- data/vendor/automerge-rust/automerge/src/cursor.rs +296 -0
- data/vendor/automerge-rust/automerge/src/decoding.rs +475 -0
- data/vendor/automerge-rust/automerge/src/error.rs +159 -0
- data/vendor/automerge-rust/automerge/src/exid.rs +238 -0
- data/vendor/automerge-rust/automerge/src/hydrate/list.rs +140 -0
- data/vendor/automerge-rust/automerge/src/hydrate/map.rs +132 -0
- data/vendor/automerge-rust/automerge/src/hydrate/tests.rs +40 -0
- data/vendor/automerge-rust/automerge/src/hydrate/text.rs +89 -0
- data/vendor/automerge-rust/automerge/src/hydrate.rs +368 -0
- data/vendor/automerge-rust/automerge/src/indexed_cache.rs +113 -0
- data/vendor/automerge-rust/automerge/src/iter/doc.rs +603 -0
- data/vendor/automerge-rust/automerge/src/iter/keys.rs +93 -0
- data/vendor/automerge-rust/automerge/src/iter/list_range.rs +433 -0
- data/vendor/automerge-rust/automerge/src/iter/map_range.rs +316 -0
- data/vendor/automerge-rust/automerge/src/iter/spans.rs +601 -0
- data/vendor/automerge-rust/automerge/src/iter/tools.rs +427 -0
- data/vendor/automerge-rust/automerge/src/iter/values.rs +36 -0
- data/vendor/automerge-rust/automerge/src/iter.rs +25 -0
- data/vendor/automerge-rust/automerge/src/legacy/mod.rs +364 -0
- data/vendor/automerge-rust/automerge/src/legacy/serde_impls/actor_id.rs +25 -0
- data/vendor/automerge-rust/automerge/src/legacy/serde_impls/change_hash.rs +29 -0
- data/vendor/automerge-rust/automerge/src/legacy/serde_impls/element_id.rs +27 -0
- data/vendor/automerge-rust/automerge/src/legacy/serde_impls/mod.rs +31 -0
- data/vendor/automerge-rust/automerge/src/legacy/serde_impls/object_id.rs +36 -0
- data/vendor/automerge-rust/automerge/src/legacy/serde_impls/op.rs +668 -0
- data/vendor/automerge-rust/automerge/src/legacy/serde_impls/op_type.rs +26 -0
- data/vendor/automerge-rust/automerge/src/legacy/serde_impls/opid.rs +25 -0
- data/vendor/automerge-rust/automerge/src/legacy/serde_impls/scalar_value.rs +63 -0
- data/vendor/automerge-rust/automerge/src/legacy/utility_impls/element_id.rs +66 -0
- data/vendor/automerge-rust/automerge/src/legacy/utility_impls/key.rs +49 -0
- data/vendor/automerge-rust/automerge/src/legacy/utility_impls/mod.rs +4 -0
- data/vendor/automerge-rust/automerge/src/legacy/utility_impls/object_id.rs +74 -0
- data/vendor/automerge-rust/automerge/src/legacy/utility_impls/opid.rs +68 -0
- data/vendor/automerge-rust/automerge/src/lib.rs +315 -0
- data/vendor/automerge-rust/automerge/src/marks.rs +478 -0
- data/vendor/automerge-rust/automerge/src/op_set2/change/batch.rs +2002 -0
- data/vendor/automerge-rust/automerge/src/op_set2/change/collector.rs +974 -0
- data/vendor/automerge-rust/automerge/src/op_set2/change.rs +332 -0
- data/vendor/automerge-rust/automerge/src/op_set2/columns.rs +714 -0
- data/vendor/automerge-rust/automerge/src/op_set2/meta.rs +174 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op.rs +1363 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op_set/elems.rs +43 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op_set/found_op.rs +60 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op_set/index.rs +197 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op_set/insert.rs +179 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op_set/mark_index.rs +292 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op_set/marks.rs +86 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op_set/op_iter.rs +1295 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op_set/op_query.rs +82 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op_set/top_op.rs +50 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op_set/visible.rs +290 -0
- data/vendor/automerge-rust/automerge/src/op_set2/op_set.rs +1793 -0
- data/vendor/automerge-rust/automerge/src/op_set2/parents.rs +133 -0
- data/vendor/automerge-rust/automerge/src/op_set2/skip_list.rs +714 -0
- data/vendor/automerge-rust/automerge/src/op_set2/types.rs +769 -0
- data/vendor/automerge-rust/automerge/src/op_set2.rs +18 -0
- data/vendor/automerge-rust/automerge/src/patches/patch.rs +95 -0
- data/vendor/automerge-rust/automerge/src/patches/patch_builder.rs +382 -0
- data/vendor/automerge-rust/automerge/src/patches/patch_log.rs +584 -0
- data/vendor/automerge-rust/automerge/src/patches.rs +7 -0
- data/vendor/automerge-rust/automerge/src/query/list_state.rs +230 -0
- data/vendor/automerge-rust/automerge/src/query/seek_mark.rs +142 -0
- data/vendor/automerge-rust/automerge/src/read.rs +326 -0
- data/vendor/automerge-rust/automerge/src/sequence_tree.rs +662 -0
- data/vendor/automerge-rust/automerge/src/storage/bundle/builder.rs +942 -0
- data/vendor/automerge-rust/automerge/src/storage/bundle/error.rs +42 -0
- data/vendor/automerge-rust/automerge/src/storage/bundle/meta.rs +23 -0
- data/vendor/automerge-rust/automerge/src/storage/bundle/storage.rs +146 -0
- data/vendor/automerge-rust/automerge/src/storage/bundle.rs +210 -0
- data/vendor/automerge-rust/automerge/src/storage/change/change_actors.rs +311 -0
- data/vendor/automerge-rust/automerge/src/storage/change/change_op_columns.rs +621 -0
- data/vendor/automerge-rust/automerge/src/storage/change/compressed.rs +51 -0
- data/vendor/automerge-rust/automerge/src/storage/change/op_with_change_actors.rs +1 -0
- data/vendor/automerge-rust/automerge/src/storage/change.rs +523 -0
- data/vendor/automerge-rust/automerge/src/storage/chunk.rs +312 -0
- data/vendor/automerge-rust/automerge/src/storage/columns/column.rs +42 -0
- data/vendor/automerge-rust/automerge/src/storage/columns/column_builder.rs +199 -0
- data/vendor/automerge-rust/automerge/src/storage/columns/column_specification.rs +340 -0
- data/vendor/automerge-rust/automerge/src/storage/columns/raw_column.rs +286 -0
- data/vendor/automerge-rust/automerge/src/storage/columns.rs +355 -0
- data/vendor/automerge-rust/automerge/src/storage/document/compression.rs +362 -0
- data/vendor/automerge-rust/automerge/src/storage/document.rs +411 -0
- data/vendor/automerge-rust/automerge/src/storage/load/change_collector.rs +15 -0
- data/vendor/automerge-rust/automerge/src/storage/load.rs +136 -0
- data/vendor/automerge-rust/automerge/src/storage/parse/leb128.rs +302 -0
- data/vendor/automerge-rust/automerge/src/storage/parse.rs +619 -0
- data/vendor/automerge-rust/automerge/src/storage/save/document.rs +27 -0
- data/vendor/automerge-rust/automerge/src/storage.rs +26 -0
- data/vendor/automerge-rust/automerge/src/sync/bloom.rs +161 -0
- data/vendor/automerge-rust/automerge/src/sync/message_builder.rs +118 -0
- data/vendor/automerge-rust/automerge/src/sync/state.rs +214 -0
- data/vendor/automerge-rust/automerge/src/sync/v1_compat_test/bloom.rs +162 -0
- data/vendor/automerge-rust/automerge/src/sync/v1_compat_test/mod.rs +625 -0
- data/vendor/automerge-rust/automerge/src/sync/v1_compat_test/state.rs +120 -0
- data/vendor/automerge-rust/automerge/src/sync.rs +2482 -0
- data/vendor/automerge-rust/automerge/src/text_diff/LICENSE +201 -0
- data/vendor/automerge-rust/automerge/src/text_diff/myers.rs +332 -0
- data/vendor/automerge-rust/automerge/src/text_diff/replace.rs +139 -0
- data/vendor/automerge-rust/automerge/src/text_diff/utils.rs +119 -0
- data/vendor/automerge-rust/automerge/src/text_diff.rs +515 -0
- data/vendor/automerge-rust/automerge/src/text_value.rs +276 -0
- data/vendor/automerge-rust/automerge/src/transaction/commit.rs +34 -0
- data/vendor/automerge-rust/automerge/src/transaction/inner.rs +1403 -0
- data/vendor/automerge-rust/automerge/src/transaction/manual_transaction.rs +147 -0
- data/vendor/automerge-rust/automerge/src/transaction/owned_transaction.rs +266 -0
- data/vendor/automerge-rust/automerge/src/transaction/result.rs +21 -0
- data/vendor/automerge-rust/automerge/src/transaction/transactable.rs +203 -0
- data/vendor/automerge-rust/automerge/src/transaction.rs +513 -0
- data/vendor/automerge-rust/automerge/src/types.rs +749 -0
- data/vendor/automerge-rust/automerge/src/validation.rs +29 -0
- data/vendor/automerge-rust/automerge/src/value.rs +763 -0
- data/vendor/automerge-rust/automerge/tests/batch_insert.rs +1034 -0
- data/vendor/automerge-rust/automerge/tests/block_tests.rs +887 -0
- data/vendor/automerge-rust/automerge/tests/convert_string_to_text.rs +72 -0
- data/vendor/automerge-rust/automerge/tests/diff_marks.rs +1508 -0
- data/vendor/automerge-rust/automerge/tests/fixtures/64bit_obj_id_change.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fixtures/64bit_obj_id_doc.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fixtures/counter_value_has_incorrect_meta.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fixtures/counter_value_is_ok.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fixtures/counter_value_is_overlong.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fixtures/two_change_chunks.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fixtures/two_change_chunks_compressed.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fixtures/two_change_chunks_out_of_order.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fuzz-crashers/action-is-48.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fuzz-crashers/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709 +0 -0
- data/vendor/automerge-rust/automerge/tests/fuzz-crashers/incorrect_max_op.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fuzz-crashers/invalid_deflate_stream.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fuzz-crashers/missing_actor.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fuzz-crashers/overflow_in_length.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fuzz-crashers/too_many_deps.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/fuzz-crashers/too_many_ops.automerge +0 -0
- data/vendor/automerge-rust/automerge/tests/test.rs +2668 -0
- data/vendor/automerge-rust/automerge/tests/test_mark_patches.rs +41 -0
- data/vendor/automerge-rust/automerge/tests/test_save_load_orphans.rs +84 -0
- data/vendor/automerge-rust/automerge/tests/text.rs +1098 -0
- data/vendor/automerge-rust/automerge/tests/text_encoding.rs +640 -0
- data/vendor/automerge-rust/automerge-c/CMakeLists.txt +439 -0
- data/vendor/automerge-rust/automerge-c/Cargo.toml +22 -0
- data/vendor/automerge-rust/automerge-c/README.md +233 -0
- data/vendor/automerge-rust/automerge-c/build.rs +21 -0
- data/vendor/automerge-rust/automerge-c/cbindgen.toml +48 -0
- data/vendor/automerge-rust/automerge-c/cmake/Cargo.toml.in +22 -0
- data/vendor/automerge-rust/automerge-c/cmake/automerge-c-config.cmake.in +99 -0
- data/vendor/automerge-rust/automerge-c/cmake/cbindgen.toml.in +48 -0
- data/vendor/automerge-rust/automerge-c/cmake/config.h.in +58 -0
- data/vendor/automerge-rust/automerge-c/cmake/enum-string-functions-gen.cmake +183 -0
- data/vendor/automerge-rust/automerge-c/cmake/file-regex-replace.cmake +33 -0
- data/vendor/automerge-rust/automerge-c/cmake/file-touch.cmake +35 -0
- data/vendor/automerge-rust/automerge-c/docs/CMakeLists.txt +39 -0
- data/vendor/automerge-rust/automerge-c/docs/img/brandmark.png +0 -0
- data/vendor/automerge-rust/automerge-c/examples/CMakeLists.txt +42 -0
- data/vendor/automerge-rust/automerge-c/examples/README.md +9 -0
- data/vendor/automerge-rust/automerge-c/examples/quickstart.c +131 -0
- data/vendor/automerge-rust/automerge-c/include/automerge-c/utils/result.h +30 -0
- data/vendor/automerge-rust/automerge-c/include/automerge-c/utils/stack.h +130 -0
- data/vendor/automerge-rust/automerge-c/include/automerge-c/utils/stack_callback_data.h +53 -0
- data/vendor/automerge-rust/automerge-c/include/automerge-c/utils/string.h +29 -0
- data/vendor/automerge-rust/automerge-c/src/actor_id.rs +193 -0
- data/vendor/automerge-rust/automerge-c/src/byte_span.rs +227 -0
- data/vendor/automerge-rust/automerge-c/src/change.rs +356 -0
- data/vendor/automerge-rust/automerge-c/src/cursor.rs +168 -0
- data/vendor/automerge-rust/automerge-c/src/doc/list.rs +636 -0
- data/vendor/automerge-rust/automerge-c/src/doc/map.rs +556 -0
- data/vendor/automerge-rust/automerge-c/src/doc/mark.rs +296 -0
- data/vendor/automerge-rust/automerge-c/src/doc/utils.rs +46 -0
- data/vendor/automerge-rust/automerge-c/src/doc.rs +1009 -0
- data/vendor/automerge-rust/automerge-c/src/index.rs +84 -0
- data/vendor/automerge-rust/automerge-c/src/item.rs +2177 -0
- data/vendor/automerge-rust/automerge-c/src/items.rs +401 -0
- data/vendor/automerge-rust/automerge-c/src/lib.rs +11 -0
- data/vendor/automerge-rust/automerge-c/src/obj.rs +216 -0
- data/vendor/automerge-rust/automerge-c/src/result.rs +653 -0
- data/vendor/automerge-rust/automerge-c/src/sync/have.rs +42 -0
- data/vendor/automerge-rust/automerge-c/src/sync/message.rs +146 -0
- data/vendor/automerge-rust/automerge-c/src/sync/state.rs +262 -0
- data/vendor/automerge-rust/automerge-c/src/sync.rs +7 -0
- data/vendor/automerge-rust/automerge-c/src/utils/result.c +33 -0
- data/vendor/automerge-rust/automerge-c/src/utils/stack.c +106 -0
- data/vendor/automerge-rust/automerge-c/src/utils/stack_callback_data.c +9 -0
- data/vendor/automerge-rust/automerge-c/src/utils/string.c +46 -0
- data/vendor/automerge-rust/automerge-c/test/CMakeLists.txt +67 -0
- data/vendor/automerge-rust/automerge-c/test/actor_id_tests.c +140 -0
- data/vendor/automerge-rust/automerge-c/test/base_state.c +17 -0
- data/vendor/automerge-rust/automerge-c/test/base_state.h +39 -0
- data/vendor/automerge-rust/automerge-c/test/byte_span_tests.c +119 -0
- data/vendor/automerge-rust/automerge-c/test/cmocka_utils.c +91 -0
- data/vendor/automerge-rust/automerge-c/test/cmocka_utils.h +42 -0
- data/vendor/automerge-rust/automerge-c/test/cursor_tests.c +263 -0
- data/vendor/automerge-rust/automerge-c/test/doc_state.c +27 -0
- data/vendor/automerge-rust/automerge-c/test/doc_state.h +17 -0
- data/vendor/automerge-rust/automerge-c/test/doc_tests.c +335 -0
- data/vendor/automerge-rust/automerge-c/test/enum_string_tests.c +148 -0
- data/vendor/automerge-rust/automerge-c/test/files/brave-ape-49.automerge +0 -0
- data/vendor/automerge-rust/automerge-c/test/item_tests.c +313 -0
- data/vendor/automerge-rust/automerge-c/test/list_tests.c +544 -0
- data/vendor/automerge-rust/automerge-c/test/macro_utils.c +38 -0
- data/vendor/automerge-rust/automerge-c/test/macro_utils.h +23 -0
- data/vendor/automerge-rust/automerge-c/test/main.c +33 -0
- data/vendor/automerge-rust/automerge-c/test/map_tests.c +1610 -0
- data/vendor/automerge-rust/automerge-c/test/mark_tests.c +124 -0
- data/vendor/automerge-rust/automerge-c/test/ported_wasm/basic_tests.c +1642 -0
- data/vendor/automerge-rust/automerge-c/test/ported_wasm/cursor_tests.c +108 -0
- data/vendor/automerge-rust/automerge-c/test/ported_wasm/suite.c +17 -0
- data/vendor/automerge-rust/automerge-c/test/ported_wasm/sync_tests.c +1280 -0
- data/vendor/automerge-rust/automerge-c/test/str_utils.c +15 -0
- data/vendor/automerge-rust/automerge-c/test/str_utils.h +17 -0
- data/vendor/automerge-rust/automerge-test/Cargo.toml +17 -0
- data/vendor/automerge-rust/automerge-test/README.md +3 -0
- data/vendor/automerge-rust/automerge-test/src/lib.rs +487 -0
- data/vendor/automerge-rust/hexane/CHANGELOG.md +34 -0
- data/vendor/automerge-rust/hexane/Cargo.toml +47 -0
- data/vendor/automerge-rust/hexane/README.md +292 -0
- data/vendor/automerge-rust/hexane/RESULTS.txt +20 -0
- data/vendor/automerge-rust/hexane/TODO +18 -0
- data/vendor/automerge-rust/hexane/benches/insert.rs +82 -0
- data/vendor/automerge-rust/hexane/benches/seek.rs +77 -0
- data/vendor/automerge-rust/hexane/benches/splice.rs +82 -0
- data/vendor/automerge-rust/hexane/src/aggregate.rs +288 -0
- data/vendor/automerge-rust/hexane/src/boolean.rs +478 -0
- data/vendor/automerge-rust/hexane/src/columndata.rs +2540 -0
- data/vendor/automerge-rust/hexane/src/cursor.rs +756 -0
- data/vendor/automerge-rust/hexane/src/delta.rs +793 -0
- data/vendor/automerge-rust/hexane/src/encoder.rs +639 -0
- data/vendor/automerge-rust/hexane/src/leb128.rs +82 -0
- data/vendor/automerge-rust/hexane/src/lib.rs +95 -0
- data/vendor/automerge-rust/hexane/src/pack.rs +325 -0
- data/vendor/automerge-rust/hexane/src/raw.rs +314 -0
- data/vendor/automerge-rust/hexane/src/rle.rs +928 -0
- data/vendor/automerge-rust/hexane/src/slab/tree.rs +1373 -0
- data/vendor/automerge-rust/hexane/src/slab/writer.rs +535 -0
- data/vendor/automerge-rust/hexane/src/slab.rs +224 -0
- data/vendor/automerge-rust/hexane/src/test.rs +108 -0
- data/vendor/bundle/ruby/3.3.0/bin/rake +29 -0
- data/vendor/bundle/ruby/3.3.0/bin/rake-compiler +29 -0
- data/vendor/bundle/ruby/3.3.0/bin/rake-compiler-dock +29 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/History.rdoc +1732 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/Manifest.txt +32 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/README.rdoc +845 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/Rakefile +97 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/design_rationale.rb +54 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/hoe/minitest.rb +30 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/assertions.rb +850 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/autorun.rb +6 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/benchmark.rb +452 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/compress.rb +94 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/error_on_warning.rb +11 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/expectations.rb +321 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/hell.rb +11 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/manual_plugins.rb +16 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/mock.rb +327 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/parallel.rb +72 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/pride.rb +4 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/pride_plugin.rb +135 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/spec.rb +353 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/test.rb +238 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/test_task.rb +324 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest/unit.rb +42 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/lib/minitest.rb +1250 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/test/minitest/metametameta.rb +150 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/test/minitest/test_minitest_assertions.rb +1677 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/test/minitest/test_minitest_benchmark.rb +137 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/test/minitest/test_minitest_mock.rb +1213 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/test/minitest/test_minitest_reporter.rb +437 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/test/minitest/test_minitest_spec.rb +1159 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/test/minitest/test_minitest_test.rb +1374 -0
- data/vendor/bundle/ruby/3.3.0/gems/minitest-5.27.0/test/minitest/test_minitest_test_task.rb +57 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/History.rdoc +2454 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/MIT-LICENSE +21 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/README.rdoc +155 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/command_line_usage.rdoc +171 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/example/Rakefile1 +38 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/example/Rakefile2 +35 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/example/a.c +6 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/example/b.c +6 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/example/main.c +11 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/glossary.rdoc +42 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/jamis.rb +592 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/proto_rake.rdoc +127 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/rake.1 +156 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/rakefile.rdoc +635 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/doc/rational.rdoc +151 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/exe/rake +27 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/application.rb +847 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/backtrace.rb +25 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/clean.rb +78 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/cloneable.rb +17 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/cpu_counter.rb +122 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/default_loader.rb +15 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/dsl_definition.rb +196 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/early_time.rb +22 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/ext/core.rb +26 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/ext/string.rb +176 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/file_creation_task.rb +25 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/file_list.rb +435 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/file_task.rb +58 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/file_utils.rb +137 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/file_utils_ext.rb +135 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/invocation_chain.rb +57 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/invocation_exception_mixin.rb +17 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/late_time.rb +18 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/linked_list.rb +112 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/loaders/makefile.rb +54 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/multi_task.rb +14 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/name_space.rb +38 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/options.rb +31 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/packagetask.rb +222 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/phony.rb +16 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/private_reader.rb +21 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/promise.rb +100 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/pseudo_status.rb +30 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/rake_module.rb +67 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/rake_test_loader.rb +27 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/rule_recursion_overflow_error.rb +20 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/scope.rb +43 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/task.rb +434 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/task_argument_error.rb +8 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/task_arguments.rb +113 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/task_manager.rb +333 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/tasklib.rb +12 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/testtask.rb +192 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/thread_history_display.rb +49 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/thread_pool.rb +157 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/trace_output.rb +23 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/version.rb +10 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake/win32.rb +17 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/lib/rake.rb +69 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-13.4.2/rake.gemspec +102 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/Gemfile +8 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/History.md +695 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/LICENSE.txt +20 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/README.md +476 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/Rakefile +15 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/appveyor.yml +22 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/bin/rake-compiler +24 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/cucumber.yml +4 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/compile.feature +79 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/cross-compile.feature +23 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/cross-package-multi.feature +15 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/cross-package.feature +14 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/java-compile.feature +22 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/java-no-native-compile.feature +33 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/java-package.feature +24 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/package.feature +40 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/step_definitions/compilation.rb +70 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/step_definitions/cross_compilation.rb +27 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/step_definitions/execution.rb +52 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/step_definitions/folders.rb +32 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/step_definitions/gem.rb +46 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/step_definitions/java_compilation.rb +7 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/support/env.rb +10 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/support/file_template_helpers.rb +137 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/support/generator_helpers.rb +123 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/features/support/platform_extension_helpers.rb +27 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/lib/rake/baseextensiontask.rb +90 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/lib/rake/compiler_config.rb +38 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/lib/rake/extensioncompiler.rb +51 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/lib/rake/extensiontask.rb +589 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/lib/rake/javaextensiontask.rb +321 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/tasks/bin/cross-ruby.rake +189 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/tasks/bootstrap.rake +11 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/tasks/common.rake +10 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/tasks/cucumber.rake +23 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/tasks/gem.rake +15 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-1.3.1/tasks/rspec.rake +9 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/CHANGELOG.md +446 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/CONTRIBUTING.md +109 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/Dockerfile.jruby +79 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/Dockerfile.mri.erb +282 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/Gemfile +8 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/LICENSE.txt +22 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/README.md +447 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/Rakefile +246 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/bin/rake-compiler-dock +18 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/buildkitd.toml +2 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/gem_helper.rb +54 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/mk_i686.rb +18 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/mk_musl_cross.sh +37 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/mk_osxcross.sh +45 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/mk_pkg_config.sh +24 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/parallel_docker_build.rb +169 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/patches/rake-compiler-1.3.1/0004-Enable-build-of-static-libruby.patch +38 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/patches/rake-compiler-1.3.1/0005-build-miniruby-first.patch +16 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/patches/rake-compiler-1.3.1/0006-ruby-4-rubyspec-capiext.patch +16 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/rcd-env.sh +6 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/runas +7 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/sigfw.c +45 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/strip_wrapper_codesign +17 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/strip_wrapper_vbox +30 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/build/sudoers +1 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock/colors.rb +43 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock/docker_check.rb +356 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock/predefined_user_group.rb +5 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock/starter.rb +206 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock/version.rb +4 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/lib/rake_compiler_dock.rb +151 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/mingw64-ucrt/Dockerfile +66 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/mingw64-ucrt/README.md +14 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/mingw64-ucrt/binutils-mingw-w64-ignore-check-errors.patch +13 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/mingw64-ucrt/gcc-mingw-w64-only-c-c++.patch +13 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/mingw64-ucrt/mingw-w64-enable-ucrt.patch +22 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/rake-compiler-dock.gemspec +34 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/env/Dockerfile.alpine +17 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/env/Dockerfile.debian +24 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/fixtures/mig_test_rpc.defs +8 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/Gemfile +11 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/Rakefile +97 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/ext/java/RcdTestExtService.java +19 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/ext/java/RubyRcdTest.java +16 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/ext/mri/extconf.rb +111 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/ext/mri/rcd_test_ext.c +65 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/ext/mri/rcd_test_ext.h +11 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/lib/rcd_test.rb +6 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/rcd_test.gemspec +28 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/rcd_test/test/test_basic.rb +49 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/test_environment_variables.rb +108 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/test_mig.rb +18 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/test_parallel_docker_build.rb +95 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/test_rubygems_plugins.rb +12 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/test_starter.rb +158 -0
- data/vendor/bundle/ruby/3.3.0/gems/rake-compiler-dock-1.12.0/test/test_versions.rb +82 -0
- data/vendor/bundle/ruby/3.3.0/specifications/minitest-5.27.0.gemspec +32 -0
- data/vendor/bundle/ruby/3.3.0/specifications/rake-13.4.2.gemspec +26 -0
- data/vendor/bundle/ruby/3.3.0/specifications/rake-compiler-1.3.1.gemspec +33 -0
- data/vendor/bundle/ruby/3.3.0/specifications/rake-compiler-dock-1.12.0.gemspec +28 -0
- metadata +584 -0
|
@@ -0,0 +1,2071 @@
|
|
|
1
|
+
use std::cmp::Ordering;
|
|
2
|
+
use std::collections::{BTreeSet, HashSet};
|
|
3
|
+
use std::env;
|
|
4
|
+
use std::fmt::Debug;
|
|
5
|
+
use std::num::NonZeroU64;
|
|
6
|
+
use std::ops::RangeBounds;
|
|
7
|
+
|
|
8
|
+
use itertools::Itertools;
|
|
9
|
+
|
|
10
|
+
pub(crate) use crate::op_set2::change::ChangeCollector;
|
|
11
|
+
pub(crate) use crate::op_set2::types::ScalarValue;
|
|
12
|
+
pub(crate) use crate::op_set2::{
|
|
13
|
+
ChangeMetadata, KeyRef, OpQuery, OpQueryTerm, OpSet, OpType, Parents,
|
|
14
|
+
};
|
|
15
|
+
pub(crate) use crate::read::ReadDoc;
|
|
16
|
+
|
|
17
|
+
use crate::change_graph::ChangeGraph;
|
|
18
|
+
use crate::change_queue::ChangeQueue;
|
|
19
|
+
use crate::cursor::{CursorPosition, MoveCursor, OpCursor};
|
|
20
|
+
use crate::exid::ExId;
|
|
21
|
+
use crate::iter::{DiffIter, DocIter, Keys, ListRange, MapRange, Spans, Values};
|
|
22
|
+
use crate::marks::{Mark, MarkAccumulator, MarkSet};
|
|
23
|
+
use crate::patches::{Patch, PatchLog};
|
|
24
|
+
use crate::storage::{self, change, load, Bundle, CompressConfig, Document, VerificationMode};
|
|
25
|
+
use crate::transaction::{
|
|
26
|
+
self, CommitOptions, Failure, OwnedTransaction, Success, Transactable, Transaction,
|
|
27
|
+
TransactionArgs,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
use crate::clock::{Clock, ClockRange};
|
|
31
|
+
use crate::hydrate;
|
|
32
|
+
use crate::types::{ActorId, ChangeHash, ObjId, ObjMeta, OpId, SequenceType, TextEncoding, Value};
|
|
33
|
+
use crate::{AutomergeError, Change, Cursor, ObjType, Prop};
|
|
34
|
+
|
|
35
|
+
pub(crate) mod current_state;
|
|
36
|
+
|
|
37
|
+
// FIXME
|
|
38
|
+
//#[cfg(test)]
|
|
39
|
+
//mod tests;
|
|
40
|
+
|
|
41
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
42
|
+
pub(crate) enum Actor {
|
|
43
|
+
Unused(ActorId),
|
|
44
|
+
Cached(usize),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
impl Actor {
|
|
48
|
+
fn remove_actor(&mut self, index: usize, actors: &[ActorId]) {
|
|
49
|
+
if let Actor::Cached(idx) = self {
|
|
50
|
+
match (*idx).cmp(&index) {
|
|
51
|
+
Ordering::Equal => *self = Actor::Unused(actors[index].clone()),
|
|
52
|
+
Ordering::Greater => *idx -= 1,
|
|
53
|
+
Ordering::Less => (),
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fn rewrite_with_new_actor(&mut self, index: usize) {
|
|
59
|
+
if let Actor::Cached(idx) = self {
|
|
60
|
+
if *idx >= index {
|
|
61
|
+
*idx += 1;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// What to do when loading a document partially succeeds
|
|
68
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
69
|
+
pub enum OnPartialLoad {
|
|
70
|
+
/// Ignore the error and return the loaded changes
|
|
71
|
+
Ignore,
|
|
72
|
+
/// Fail the entire load
|
|
73
|
+
Error,
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/// Whether to convert [`ScalarValue::Str`]s in the loaded document to [`ObjType::Text`]
|
|
77
|
+
#[derive(Debug)]
|
|
78
|
+
pub enum StringMigration {
|
|
79
|
+
/// Don't convert anything
|
|
80
|
+
NoMigration,
|
|
81
|
+
/// Convert all strings to text
|
|
82
|
+
ConvertToText,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
#[derive(Debug)]
|
|
86
|
+
pub struct LoadOptions<'a> {
|
|
87
|
+
on_partial_load: OnPartialLoad,
|
|
88
|
+
verification_mode: VerificationMode,
|
|
89
|
+
string_migration: StringMigration,
|
|
90
|
+
patch_log: Option<&'a mut PatchLog>,
|
|
91
|
+
text_encoding: TextEncoding,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
impl<'a> LoadOptions<'a> {
|
|
95
|
+
pub fn new() -> LoadOptions<'static> {
|
|
96
|
+
LoadOptions::default()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// What to do when loading a document partially succeeds
|
|
100
|
+
///
|
|
101
|
+
/// The default is [`OnPartialLoad::Error`]
|
|
102
|
+
pub fn on_partial_load(self, on_partial_load: OnPartialLoad) -> Self {
|
|
103
|
+
Self {
|
|
104
|
+
on_partial_load,
|
|
105
|
+
..self
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/// Whether to verify the head hashes after loading
|
|
110
|
+
///
|
|
111
|
+
/// The default is [`VerificationMode::Check`]
|
|
112
|
+
pub fn verification_mode(self, verification_mode: VerificationMode) -> Self {
|
|
113
|
+
Self {
|
|
114
|
+
verification_mode,
|
|
115
|
+
..self
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/// A [`PatchLog`] to log the changes required to materialize the current state of the
|
|
120
|
+
///
|
|
121
|
+
/// The default is to not log patches
|
|
122
|
+
pub fn patch_log(self, patch_log: &'a mut PatchLog) -> Self {
|
|
123
|
+
Self {
|
|
124
|
+
patch_log: Some(patch_log),
|
|
125
|
+
..self
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/// Whether to convert [`ScalarValue::Str`]s in the loaded document to [`ObjType::Text`]
|
|
130
|
+
///
|
|
131
|
+
/// Until version 2.1.0 of the javascript library strings (as in, the native string of the JS
|
|
132
|
+
/// runtime) were represented in the document as [`ScalarValue::Str`] and there was a special
|
|
133
|
+
/// JS class called `Text` which users were expected to use for [`ObjType::Text`]. In `2.1.0`
|
|
134
|
+
/// we changed this so that native strings were represented as [`ObjType::Text`] and
|
|
135
|
+
/// [`ScalarValue::Str`] was represented as a special `RawString` class. This means
|
|
136
|
+
/// that upgrading the application code to use the new API would require either
|
|
137
|
+
///
|
|
138
|
+
/// a) Maintaining two code paths in the application to deal with both `string` and `RawString`
|
|
139
|
+
/// types
|
|
140
|
+
/// b) Writing a migration script to convert all `RawString` types to `string`
|
|
141
|
+
///
|
|
142
|
+
/// The latter is logic which is the same for all applications so we implement it in the
|
|
143
|
+
/// library for convenience. The way this works is that after loading the document we iterate
|
|
144
|
+
/// through all visible [`ScalarValue::Str`] values and emit a change which creates a new
|
|
145
|
+
/// [`ObjType::Text`] at the same path with the same content.
|
|
146
|
+
pub fn migrate_strings(self, migration: StringMigration) -> Self {
|
|
147
|
+
Self {
|
|
148
|
+
string_migration: migration,
|
|
149
|
+
..self
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
pub fn text_encoding(self, text_encoding: TextEncoding) -> Self {
|
|
154
|
+
Self {
|
|
155
|
+
text_encoding,
|
|
156
|
+
..self
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
impl std::default::Default for LoadOptions<'static> {
|
|
162
|
+
fn default() -> Self {
|
|
163
|
+
Self {
|
|
164
|
+
on_partial_load: OnPartialLoad::Error,
|
|
165
|
+
verification_mode: VerificationMode::Check,
|
|
166
|
+
patch_log: None,
|
|
167
|
+
string_migration: StringMigration::NoMigration,
|
|
168
|
+
text_encoding: TextEncoding::platform_default(),
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/// An automerge document which does not manage transactions for you.
|
|
174
|
+
///
|
|
175
|
+
/// ## Creating, loading, merging and forking documents
|
|
176
|
+
///
|
|
177
|
+
/// A new document can be created with [`Self::new()`], which will create a document with a random
|
|
178
|
+
/// [`ActorId`]. Existing documents can be loaded with [`Self::load()`], or [`Self::load_with()`].
|
|
179
|
+
///
|
|
180
|
+
/// If you have two documents and you want to merge the changes from one into the other you can use
|
|
181
|
+
/// [`Self::merge()`] or [`Self::merge_and_log_patches()`].
|
|
182
|
+
///
|
|
183
|
+
/// If you have a document you want to split into two concurrent threads of execution you can use
|
|
184
|
+
/// [`Self::fork()`]. If you want to split a document from ealier in its history you can use
|
|
185
|
+
/// [`Self::fork_at()`].
|
|
186
|
+
///
|
|
187
|
+
/// ## Reading values
|
|
188
|
+
///
|
|
189
|
+
/// [`Self`] implements [`ReadDoc`], which provides methods for reading values from the document.
|
|
190
|
+
///
|
|
191
|
+
/// ## Modifying a document (Transactions)
|
|
192
|
+
///
|
|
193
|
+
/// [`Automerge`] provides an interface for viewing and modifying automerge documents which does
|
|
194
|
+
/// not manage transactions for you. To create changes you use either [`Automerge::transaction()`] or
|
|
195
|
+
/// [`Automerge::transact()`] (or the `_with` variants).
|
|
196
|
+
///
|
|
197
|
+
/// ## Sync
|
|
198
|
+
///
|
|
199
|
+
/// This type implements [`crate::sync::SyncDoc`]
|
|
200
|
+
///
|
|
201
|
+
#[derive(Debug, Clone)]
|
|
202
|
+
pub struct Automerge {
|
|
203
|
+
/// The list of unapplied changes that are not causally ready.
|
|
204
|
+
pub(crate) queue: ChangeQueue,
|
|
205
|
+
/// Graph of changes
|
|
206
|
+
pub(crate) change_graph: ChangeGraph,
|
|
207
|
+
/// Current dependencies of this document (heads hashes).
|
|
208
|
+
deps: HashSet<ChangeHash>,
|
|
209
|
+
/// The set of operations that form this document.
|
|
210
|
+
pub(crate) ops: OpSet,
|
|
211
|
+
/// The current actor.
|
|
212
|
+
actor: Actor,
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
impl Automerge {
|
|
216
|
+
/// Create a new document with a random actor id.
|
|
217
|
+
pub fn new() -> Self {
|
|
218
|
+
Automerge {
|
|
219
|
+
queue: ChangeQueue::new(),
|
|
220
|
+
change_graph: ChangeGraph::new(0),
|
|
221
|
+
ops: OpSet::new(TextEncoding::platform_default()),
|
|
222
|
+
deps: Default::default(),
|
|
223
|
+
actor: Actor::Unused(ActorId::random()),
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/// Overwrite the keys of the root object with the values from `value`
|
|
228
|
+
///
|
|
229
|
+
/// This is useful to initialize an empty document with a large initial
|
|
230
|
+
/// value. Note that existing keys which are not in `value` are left as is
|
|
231
|
+
pub fn init_from_hydrate(&mut self, value: &crate::hydrate::Map) -> Result<(), AutomergeError> {
|
|
232
|
+
let mut tx = self.transaction();
|
|
233
|
+
tx.batch_init_root_map(value)?;
|
|
234
|
+
tx.commit();
|
|
235
|
+
Ok(())
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
pub fn new_with_encoding(encoding: TextEncoding) -> Self {
|
|
239
|
+
Automerge {
|
|
240
|
+
queue: ChangeQueue::new(),
|
|
241
|
+
change_graph: ChangeGraph::new(0),
|
|
242
|
+
ops: OpSet::new(encoding),
|
|
243
|
+
deps: Default::default(),
|
|
244
|
+
actor: Actor::Unused(ActorId::random()),
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
pub(crate) fn from_parts(ops: OpSet, change_graph: ChangeGraph) -> Self {
|
|
249
|
+
let deps = change_graph.heads().collect();
|
|
250
|
+
let mut doc = Automerge {
|
|
251
|
+
queue: ChangeQueue::new(),
|
|
252
|
+
change_graph,
|
|
253
|
+
ops,
|
|
254
|
+
deps,
|
|
255
|
+
actor: Actor::Unused(ActorId::random()),
|
|
256
|
+
};
|
|
257
|
+
doc.remove_unused_actors(false);
|
|
258
|
+
doc
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
pub(crate) fn ops_mut(&mut self) -> &mut OpSet {
|
|
262
|
+
&mut self.ops
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
pub(crate) fn ops(&self) -> &OpSet {
|
|
266
|
+
&self.ops
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
pub(crate) fn changes(&self) -> &ChangeGraph {
|
|
270
|
+
&self.change_graph
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/// Whether this document has any operations
|
|
274
|
+
pub fn is_empty(&self) -> bool {
|
|
275
|
+
self.change_graph.is_empty() && self.queue.is_empty()
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
pub(crate) fn actor_id(&self) -> &ActorId {
|
|
279
|
+
match &self.actor {
|
|
280
|
+
Actor::Unused(id) => id,
|
|
281
|
+
Actor::Cached(idx) => self.ops.get_actor(*idx),
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/// Set the actor id for this document.
|
|
286
|
+
pub fn with_actor(mut self, actor: ActorId) -> Self {
|
|
287
|
+
self.set_actor(actor);
|
|
288
|
+
self
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/// Set the actor id for this document.
|
|
292
|
+
pub fn set_actor(&mut self, actor: ActorId) -> &mut Self {
|
|
293
|
+
match self.ops.actors.binary_search(&actor) {
|
|
294
|
+
Ok(idx) => self.actor = Actor::Cached(idx),
|
|
295
|
+
Err(_) => self.actor = Actor::Unused(actor),
|
|
296
|
+
}
|
|
297
|
+
self
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/// Get the current actor id of this document.
|
|
301
|
+
pub fn get_actor(&self) -> &ActorId {
|
|
302
|
+
match &self.actor {
|
|
303
|
+
Actor::Unused(actor) => actor,
|
|
304
|
+
Actor::Cached(index) => self.ops.get_actor(*index),
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
pub(crate) fn remove_actor(&mut self, actor: usize) {
|
|
309
|
+
self.actor.remove_actor(actor, &self.ops.actors);
|
|
310
|
+
self.ops.remove_actor(actor);
|
|
311
|
+
self.change_graph.remove_actor(actor);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
pub(crate) fn assert_no_unused_actors(&self, panic: bool) {
|
|
315
|
+
if self.ops.actors.len() != self.change_graph.actor_ids().count() {
|
|
316
|
+
let unused = self.change_graph.unused_actors().collect::<Vec<_>>();
|
|
317
|
+
log!("AUTOMERGE :: unused actor found when none expected");
|
|
318
|
+
log!(" :: ops={}", self.ops.actors.len());
|
|
319
|
+
log!(" :: graph={}", self.change_graph.all_actor_ids().count());
|
|
320
|
+
log!(" :: unused={:?}", unused);
|
|
321
|
+
log!(" :: actors={:?}", self.ops.actors);
|
|
322
|
+
assert!(!panic);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
pub(crate) fn remove_unused_actors(&mut self, panic: bool) {
|
|
327
|
+
if panic {
|
|
328
|
+
self.assert_no_unused_actors(cfg!(debug_assertions));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// remove the offending actors
|
|
332
|
+
while let Some(idx) = self.change_graph.unused_actors().last() {
|
|
333
|
+
self.remove_actor(idx);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
fn get_or_create_actor_index(&mut self) -> usize {
|
|
338
|
+
match &self.actor {
|
|
339
|
+
Actor::Unused(actor) => {
|
|
340
|
+
let index = self.put_actor(actor.clone());
|
|
341
|
+
self.actor = Actor::Cached(index);
|
|
342
|
+
index
|
|
343
|
+
}
|
|
344
|
+
Actor::Cached(index) => *index,
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
fn get_actor_index(&self) -> Option<usize> {
|
|
349
|
+
match &self.actor {
|
|
350
|
+
Actor::Unused(_) => None,
|
|
351
|
+
Actor::Cached(index) => Some(*index),
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/// Start a transaction.
|
|
356
|
+
pub fn transaction(&mut self) -> Transaction<'_> {
|
|
357
|
+
let args = self.transaction_args(None);
|
|
358
|
+
Transaction::new(self, args, PatchLog::inactive())
|
|
359
|
+
.expect("inactive patch log should not mismatch")
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/// Start a transaction which records changes in a [`PatchLog`]
|
|
363
|
+
///
|
|
364
|
+
/// Returns [`PatchLogMismatch`](crate::PatchLogMismatch) if `patch_log` does not belong to
|
|
365
|
+
/// this document. This probably means a patch log created for one document was reused with
|
|
366
|
+
/// another document.
|
|
367
|
+
pub fn transaction_log_patches(
|
|
368
|
+
&mut self,
|
|
369
|
+
patch_log: PatchLog,
|
|
370
|
+
) -> Result<Transaction<'_>, crate::PatchLogMismatch> {
|
|
371
|
+
let args = self.transaction_args(None);
|
|
372
|
+
Transaction::new(self, args, patch_log)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/// Start a transaction isolated at a given heads
|
|
376
|
+
///
|
|
377
|
+
/// Returns [`PatchLogMismatch`](crate::PatchLogMismatch) if `patch_log` does not belong to
|
|
378
|
+
/// this document. This probably means a patch log created for one document was reused with
|
|
379
|
+
/// another document.
|
|
380
|
+
pub fn transaction_at(
|
|
381
|
+
&mut self,
|
|
382
|
+
patch_log: PatchLog,
|
|
383
|
+
heads: &[ChangeHash],
|
|
384
|
+
) -> Result<Transaction<'_>, crate::PatchLogMismatch> {
|
|
385
|
+
let args = self.transaction_args(Some(heads));
|
|
386
|
+
Transaction::new(self, args, patch_log)
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/// Start a transaction that owns the document, consuming `self`.
|
|
390
|
+
///
|
|
391
|
+
/// This is useful when the transaction must be `'static` (e.g. storing across an FFI
|
|
392
|
+
/// boundary or in a struct that requires `'static`). The document is returned when the
|
|
393
|
+
/// transaction is committed or rolled back.
|
|
394
|
+
///
|
|
395
|
+
/// # Arguments
|
|
396
|
+
/// * `patch_log` - An optional [`PatchLog`] to log the changes in this transaction to
|
|
397
|
+
/// * `heads` - An optional set of heads to isolate this transaction at, or `None` to use the
|
|
398
|
+
/// current heads of the document
|
|
399
|
+
///
|
|
400
|
+
/// Returns [`PatchLogMismatch`](crate::PatchLogMismatch) if `patch_log` does not belong to
|
|
401
|
+
/// this document. This probably means a patch log created for one document was reused with
|
|
402
|
+
/// another document.
|
|
403
|
+
pub fn into_transaction(
|
|
404
|
+
self,
|
|
405
|
+
patch_log: Option<PatchLog>,
|
|
406
|
+
heads: Option<&[ChangeHash]>,
|
|
407
|
+
) -> Result<OwnedTransaction, crate::PatchLogMismatch> {
|
|
408
|
+
OwnedTransaction::new(self, patch_log, heads)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
pub(crate) fn transaction_args(&mut self, heads: Option<&[ChangeHash]>) -> TransactionArgs {
|
|
412
|
+
let actor_index;
|
|
413
|
+
let seq;
|
|
414
|
+
let mut deps;
|
|
415
|
+
let scope;
|
|
416
|
+
match heads {
|
|
417
|
+
Some(heads) => {
|
|
418
|
+
deps = heads.to_vec();
|
|
419
|
+
let isolation = self.isolate_actor(heads);
|
|
420
|
+
actor_index = isolation.actor_index;
|
|
421
|
+
seq = isolation.seq;
|
|
422
|
+
scope = Some(isolation.clock);
|
|
423
|
+
}
|
|
424
|
+
None => {
|
|
425
|
+
actor_index = self.get_or_create_actor_index();
|
|
426
|
+
seq = self.change_graph.seq_for_actor(actor_index) + 1;
|
|
427
|
+
deps = self.get_heads();
|
|
428
|
+
scope = None;
|
|
429
|
+
if seq > 1 {
|
|
430
|
+
let last_hash = self.get_hash(actor_index, seq - 1).unwrap();
|
|
431
|
+
if !deps.contains(&last_hash) {
|
|
432
|
+
deps.push(last_hash);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// SAFETY: this unwrap is safe as we always add 1
|
|
439
|
+
let start_op = NonZeroU64::new(self.change_graph.max_op() + 1).unwrap();
|
|
440
|
+
let checkpoint = self.ops.save_checkpoint();
|
|
441
|
+
TransactionArgs {
|
|
442
|
+
actor_index,
|
|
443
|
+
seq,
|
|
444
|
+
start_op,
|
|
445
|
+
deps,
|
|
446
|
+
checkpoint,
|
|
447
|
+
scope,
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/// Run a transaction on this document in a closure, automatically handling commit or rollback
|
|
452
|
+
/// afterwards.
|
|
453
|
+
pub fn transact<F, O, E>(&mut self, f: F) -> transaction::Result<O, E>
|
|
454
|
+
where
|
|
455
|
+
F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
|
|
456
|
+
{
|
|
457
|
+
self.transact_with_impl(None::<&dyn Fn(&O) -> CommitOptions>, f)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/// Like [`Self::transact()`] but with a function for generating the commit options.
|
|
461
|
+
pub fn transact_with<F, O, E, C>(&mut self, c: C, f: F) -> transaction::Result<O, E>
|
|
462
|
+
where
|
|
463
|
+
F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
|
|
464
|
+
C: FnOnce(&O) -> CommitOptions,
|
|
465
|
+
{
|
|
466
|
+
// FIXME
|
|
467
|
+
self.transact_with_impl(Some(c), f)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
fn transact_with_impl<F, O, E, C>(&mut self, c: Option<C>, f: F) -> transaction::Result<O, E>
|
|
471
|
+
where
|
|
472
|
+
F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
|
|
473
|
+
C: FnOnce(&O) -> CommitOptions,
|
|
474
|
+
{
|
|
475
|
+
let mut tx = self.transaction();
|
|
476
|
+
let result = f(&mut tx);
|
|
477
|
+
match result {
|
|
478
|
+
Ok(result) => {
|
|
479
|
+
let (hash, patch_log) = if let Some(c) = c {
|
|
480
|
+
let commit_options = c(&result);
|
|
481
|
+
tx.commit_with(commit_options)
|
|
482
|
+
} else {
|
|
483
|
+
tx.commit()
|
|
484
|
+
};
|
|
485
|
+
Ok(Success {
|
|
486
|
+
result,
|
|
487
|
+
hash,
|
|
488
|
+
patch_log,
|
|
489
|
+
})
|
|
490
|
+
}
|
|
491
|
+
Err(error) => Err(Failure {
|
|
492
|
+
error,
|
|
493
|
+
cancelled: tx.rollback(),
|
|
494
|
+
}),
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/// Run a transaction on this document in a closure, collecting patches, automatically handling commit or rollback
|
|
499
|
+
/// afterwards.
|
|
500
|
+
///
|
|
501
|
+
/// The collected patches are available in the return value of [`Transaction::commit()`]
|
|
502
|
+
pub fn transact_and_log_patches<F, O, E>(&mut self, f: F) -> transaction::Result<O, E>
|
|
503
|
+
where
|
|
504
|
+
F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
|
|
505
|
+
{
|
|
506
|
+
self.transact_and_log_patches_with_impl(None::<&dyn Fn(&O) -> CommitOptions>, f)
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/// Like [`Self::transact_and_log_patches()`] but with a function for generating the commit options
|
|
510
|
+
pub fn transact_and_log_patches_with<F, O, E, C>(
|
|
511
|
+
&mut self,
|
|
512
|
+
c: C,
|
|
513
|
+
f: F,
|
|
514
|
+
) -> transaction::Result<O, E>
|
|
515
|
+
where
|
|
516
|
+
F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
|
|
517
|
+
C: FnOnce(&O) -> CommitOptions,
|
|
518
|
+
{
|
|
519
|
+
self.transact_and_log_patches_with_impl(Some(c), f)
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
fn transact_and_log_patches_with_impl<F, O, E, C>(
|
|
523
|
+
&mut self,
|
|
524
|
+
c: Option<C>,
|
|
525
|
+
f: F,
|
|
526
|
+
) -> transaction::Result<O, E>
|
|
527
|
+
where
|
|
528
|
+
F: FnOnce(&mut Transaction<'_>) -> Result<O, E>,
|
|
529
|
+
C: FnOnce(&O) -> CommitOptions,
|
|
530
|
+
{
|
|
531
|
+
let mut tx = self
|
|
532
|
+
.transaction_log_patches(PatchLog::active())
|
|
533
|
+
.expect("new patch log should not mismatch");
|
|
534
|
+
let result = f(&mut tx);
|
|
535
|
+
match result {
|
|
536
|
+
Ok(result) => {
|
|
537
|
+
let (hash, history) = if let Some(c) = c {
|
|
538
|
+
let commit_options = c(&result);
|
|
539
|
+
tx.commit_with(commit_options)
|
|
540
|
+
} else {
|
|
541
|
+
tx.commit()
|
|
542
|
+
};
|
|
543
|
+
Ok(Success {
|
|
544
|
+
result,
|
|
545
|
+
hash,
|
|
546
|
+
patch_log: history,
|
|
547
|
+
})
|
|
548
|
+
}
|
|
549
|
+
Err(error) => Err(Failure {
|
|
550
|
+
error,
|
|
551
|
+
cancelled: tx.rollback(),
|
|
552
|
+
}),
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/// Generate an empty change
|
|
557
|
+
///
|
|
558
|
+
/// The main reason to do this is if you want to create a "merge commit", which is a change
|
|
559
|
+
/// that has all the current heads of the document as dependencies.
|
|
560
|
+
pub fn empty_commit(&mut self, opts: CommitOptions) -> ChangeHash {
|
|
561
|
+
let args = self.transaction_args(None);
|
|
562
|
+
Transaction::empty(self, args, opts)
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/// Fork this document at the current point for use by a different actor.
|
|
566
|
+
///
|
|
567
|
+
/// This will create a new actor ID for the forked document
|
|
568
|
+
pub fn fork(&self) -> Self {
|
|
569
|
+
let mut f = self.clone();
|
|
570
|
+
f.set_actor(ActorId::random());
|
|
571
|
+
f
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/// Fork this document at the given heads
|
|
575
|
+
///
|
|
576
|
+
/// This will create a new actor ID for the forked document
|
|
577
|
+
pub fn fork_at(&self, heads: &[ChangeHash]) -> Result<Self, AutomergeError> {
|
|
578
|
+
let mut seen = heads.iter().cloned().collect::<HashSet<_>>();
|
|
579
|
+
let mut heads = heads.to_vec();
|
|
580
|
+
let mut hashes = vec![];
|
|
581
|
+
while let Some(hash) = heads.pop() {
|
|
582
|
+
if !self.change_graph.has_change(&hash) {
|
|
583
|
+
return Err(AutomergeError::InvalidHash(hash));
|
|
584
|
+
}
|
|
585
|
+
for dep in self.change_graph.deps_for_hash(&hash) {
|
|
586
|
+
if !seen.contains(&dep) {
|
|
587
|
+
heads.push(dep);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
hashes.push(hash);
|
|
591
|
+
seen.insert(hash);
|
|
592
|
+
}
|
|
593
|
+
let mut f = Self::new();
|
|
594
|
+
f.set_actor(ActorId::random());
|
|
595
|
+
let changes = self.get_changes_by_hashes(hashes.into_iter().rev())?;
|
|
596
|
+
f.apply_changes(changes)?;
|
|
597
|
+
Ok(f)
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
pub(crate) fn get_changes_by_hashes<I>(&self, hashes: I) -> Result<Vec<Change>, AutomergeError>
|
|
601
|
+
where
|
|
602
|
+
I: IntoIterator<Item = ChangeHash>,
|
|
603
|
+
{
|
|
604
|
+
ChangeCollector::for_hashes(&self.ops, &self.change_graph, hashes)
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
pub(crate) fn exid_to_opid(&self, id: &ExId) -> Result<OpId, AutomergeError> {
|
|
608
|
+
match id {
|
|
609
|
+
ExId::Root => Ok(OpId::new(0, 0)),
|
|
610
|
+
ExId::Id(ctr, actor, idx) => {
|
|
611
|
+
let opid = if self.ops.get_actor_safe(*idx) == Some(actor) {
|
|
612
|
+
OpId::new(*ctr, *idx)
|
|
613
|
+
} else if let Some(backup_idx) = self.ops.lookup_actor(actor) {
|
|
614
|
+
OpId::new(*ctr, backup_idx)
|
|
615
|
+
} else {
|
|
616
|
+
return Err(AutomergeError::InvalidObjId(id.to_string()));
|
|
617
|
+
};
|
|
618
|
+
Ok(opid)
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
pub(crate) fn get_obj_meta(&self, id: ObjId) -> Result<ObjMeta, AutomergeError> {
|
|
624
|
+
if id.is_root() {
|
|
625
|
+
Ok(ObjMeta::root())
|
|
626
|
+
} else if let Some(typ) = self.ops.object_type(&id) {
|
|
627
|
+
Ok(ObjMeta { id, typ })
|
|
628
|
+
} else {
|
|
629
|
+
Err(AutomergeError::NotAnObject)
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
pub(crate) fn op_cursor_to_opid(
|
|
634
|
+
&self,
|
|
635
|
+
cursor: &OpCursor,
|
|
636
|
+
clock: Option<&Clock>,
|
|
637
|
+
) -> Result<OpId, AutomergeError> {
|
|
638
|
+
if let Some(idx) = self.ops.lookup_actor(&cursor.actor) {
|
|
639
|
+
let opid = OpId::new(cursor.ctr, idx);
|
|
640
|
+
match clock {
|
|
641
|
+
Some(clock) if !clock.covers(&opid) => {
|
|
642
|
+
Err(AutomergeError::InvalidCursor(Cursor::Op(cursor.clone())))
|
|
643
|
+
}
|
|
644
|
+
_ => Ok(opid),
|
|
645
|
+
}
|
|
646
|
+
} else {
|
|
647
|
+
Err(AutomergeError::InvalidCursor(Cursor::Op(cursor.clone())))
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
pub(crate) fn exid_to_obj(&self, id: &ExId) -> Result<ObjMeta, AutomergeError> {
|
|
652
|
+
let opid = self.exid_to_opid(id)?;
|
|
653
|
+
let obj = ObjId(opid);
|
|
654
|
+
self.get_obj_meta(obj)
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
pub(crate) fn id_to_exid(&self, id: OpId) -> ExId {
|
|
658
|
+
self.ops.id_to_exid(id)
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
pub fn diff_opset(&self, other: &Self) -> Result<(), AutomergeError> {
|
|
662
|
+
let (ops_meta1, ops_out1) = self.ops.export();
|
|
663
|
+
let (ops_meta2, ops_out2) = other.ops.export();
|
|
664
|
+
if ops_meta1 != ops_meta2 {
|
|
665
|
+
let specs: std::collections::BTreeSet<_> = ops_meta1
|
|
666
|
+
.0
|
|
667
|
+
.iter()
|
|
668
|
+
.chain(ops_meta2.0.iter())
|
|
669
|
+
.map(|c| c.spec())
|
|
670
|
+
.collect();
|
|
671
|
+
for s in specs {
|
|
672
|
+
let d1 = ops_meta1
|
|
673
|
+
.0
|
|
674
|
+
.iter()
|
|
675
|
+
.find(|c| c.spec() == s)
|
|
676
|
+
.map(|c| c.data())
|
|
677
|
+
.unwrap_or(0..0);
|
|
678
|
+
let d2 = ops_meta2
|
|
679
|
+
.0
|
|
680
|
+
.iter()
|
|
681
|
+
.find(|c| c.spec() == s)
|
|
682
|
+
.map(|c| c.data())
|
|
683
|
+
.unwrap_or(0..0);
|
|
684
|
+
let d1 = &ops_out1[d1];
|
|
685
|
+
let d2 = &ops_out2[d2];
|
|
686
|
+
if d1 != d2 {
|
|
687
|
+
log!(" s={:?}|{:?} ", s.id(), s.col_type());
|
|
688
|
+
log!(" {:?} ", d1);
|
|
689
|
+
log!(" {:?} ", d2);
|
|
690
|
+
OpSet::decode(s, d1);
|
|
691
|
+
OpSet::decode(s, d2);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
Ok(())
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/// Load a document.
|
|
699
|
+
pub fn load(data: &[u8]) -> Result<Self, AutomergeError> {
|
|
700
|
+
Self::load_with_options(data, Default::default())
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/// Load a document without verifying the head hashes
|
|
704
|
+
///
|
|
705
|
+
/// This is useful for debugging as it allows you to examine a corrupted document.
|
|
706
|
+
pub fn load_unverified_heads(data: &[u8]) -> Result<Self, AutomergeError> {
|
|
707
|
+
Self::load_with_options(
|
|
708
|
+
data,
|
|
709
|
+
LoadOptions {
|
|
710
|
+
verification_mode: VerificationMode::DontCheck,
|
|
711
|
+
..Default::default()
|
|
712
|
+
},
|
|
713
|
+
)
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/// Load a document, with options
|
|
717
|
+
///
|
|
718
|
+
/// # Arguments
|
|
719
|
+
/// * `data` - The data to load
|
|
720
|
+
/// * `on_error` - What to do if the document is only partially loaded. This can happen if some
|
|
721
|
+
/// prefix of `data` contains valid data.
|
|
722
|
+
/// * `mode` - Whether to verify the head hashes after loading
|
|
723
|
+
/// * `patch_log` - A [`PatchLog`] to log the changes required to materialize the current state of
|
|
724
|
+
/// the document once loaded
|
|
725
|
+
#[deprecated(since = "0.5.2", note = "Use `load_with_options` instead")]
|
|
726
|
+
#[tracing::instrument(skip(data), err)]
|
|
727
|
+
pub fn load_with(
|
|
728
|
+
data: &[u8],
|
|
729
|
+
on_error: OnPartialLoad,
|
|
730
|
+
mode: VerificationMode,
|
|
731
|
+
patch_log: &mut PatchLog,
|
|
732
|
+
) -> Result<Self, AutomergeError> {
|
|
733
|
+
Self::load_with_options(
|
|
734
|
+
data,
|
|
735
|
+
LoadOptions::new()
|
|
736
|
+
.on_partial_load(on_error)
|
|
737
|
+
.verification_mode(mode)
|
|
738
|
+
.patch_log(patch_log),
|
|
739
|
+
)
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/// Load a document, with options
|
|
743
|
+
///
|
|
744
|
+
/// # Arguments
|
|
745
|
+
/// * `data` - The data to load
|
|
746
|
+
/// * `options` - The options to use when loading
|
|
747
|
+
#[tracing::instrument(skip(data), err)]
|
|
748
|
+
pub fn load_with_options(
|
|
749
|
+
data: &[u8],
|
|
750
|
+
options: LoadOptions<'_>,
|
|
751
|
+
) -> Result<Self, AutomergeError> {
|
|
752
|
+
if data.is_empty() {
|
|
753
|
+
tracing::trace!("no data, initializing empty document");
|
|
754
|
+
return Ok(Self::new());
|
|
755
|
+
}
|
|
756
|
+
tracing::trace!("loading first chunk");
|
|
757
|
+
let (remaining, first_chunk) = storage::Chunk::parse(storage::parse::Input::new(data))
|
|
758
|
+
.map_err(|e| load::Error::Parse(Box::new(e)))?;
|
|
759
|
+
if !first_chunk.checksum_valid() {
|
|
760
|
+
return Err(load::Error::BadChecksum.into());
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
let mut changes = vec![];
|
|
764
|
+
let mut first_chunk_was_doc = false;
|
|
765
|
+
let mut am = match first_chunk {
|
|
766
|
+
storage::Chunk::Document(d) => {
|
|
767
|
+
tracing::trace!("first chunk is document chunk, inflating");
|
|
768
|
+
first_chunk_was_doc = true;
|
|
769
|
+
d.reconstruct(options.verification_mode, options.text_encoding)
|
|
770
|
+
.map_err(|e| load::Error::InflateDocument(Box::new(e)))?
|
|
771
|
+
}
|
|
772
|
+
storage::Chunk::Change(stored_change) => {
|
|
773
|
+
tracing::trace!("first chunk is change chunk");
|
|
774
|
+
changes.push(
|
|
775
|
+
Change::new_from_unverified(stored_change.into_owned(), None)
|
|
776
|
+
.map_err(|e| load::Error::InvalidChangeColumns(Box::new(e)))?,
|
|
777
|
+
);
|
|
778
|
+
Self::new()
|
|
779
|
+
}
|
|
780
|
+
storage::Chunk::Bundle(bundle) => {
|
|
781
|
+
tracing::trace!("first chunk is change chunk");
|
|
782
|
+
let bundle = Bundle::new_from_unverified(bundle.into_owned())
|
|
783
|
+
.map_err(|e| load::Error::InvalidBundleColumn(Box::new(e)))?;
|
|
784
|
+
let bundle_changes = bundle
|
|
785
|
+
.to_changes()
|
|
786
|
+
.map_err(|e| load::Error::InvalidBundleChange(Box::new(e)))?;
|
|
787
|
+
changes.extend(bundle_changes);
|
|
788
|
+
Self::new()
|
|
789
|
+
}
|
|
790
|
+
storage::Chunk::CompressedChange(stored_change, compressed) => {
|
|
791
|
+
tracing::trace!("first chunk is compressed change");
|
|
792
|
+
changes.push(
|
|
793
|
+
Change::new_from_unverified(
|
|
794
|
+
stored_change.into_owned(),
|
|
795
|
+
Some(compressed.into_owned()),
|
|
796
|
+
)
|
|
797
|
+
.map_err(|e| load::Error::InvalidChangeColumns(Box::new(e)))?,
|
|
798
|
+
);
|
|
799
|
+
Self::new()
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
tracing::trace!("loading change chunks");
|
|
803
|
+
match load::load_changes(remaining.reset(), options.text_encoding, &am.change_graph) {
|
|
804
|
+
load::LoadedChanges::Complete(c) => {
|
|
805
|
+
am.apply_changes(changes.into_iter().chain(c))?;
|
|
806
|
+
// Only allow missing deps if the first chunk was a document chunk
|
|
807
|
+
// See https://github.com/automerge/automerge/pull/599#issuecomment-1549667472
|
|
808
|
+
if !am.queue.is_empty()
|
|
809
|
+
&& !first_chunk_was_doc
|
|
810
|
+
&& options.on_partial_load == OnPartialLoad::Error
|
|
811
|
+
{
|
|
812
|
+
return Err(AutomergeError::MissingDeps);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
load::LoadedChanges::Partial { error, .. } => {
|
|
816
|
+
if options.on_partial_load == OnPartialLoad::Error {
|
|
817
|
+
return Err(error.into());
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
if let StringMigration::ConvertToText = options.string_migration {
|
|
822
|
+
am.convert_scalar_strings_to_text()?;
|
|
823
|
+
}
|
|
824
|
+
if let Some(patch_log) = options.patch_log {
|
|
825
|
+
if patch_log.is_active() {
|
|
826
|
+
am.log_current_state(ObjMeta::root(), patch_log, true);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
Ok(am)
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
/// Create the patches from a [`PatchLog`]
|
|
833
|
+
///
|
|
834
|
+
/// See the documentation for [`PatchLog`] for more details on this
|
|
835
|
+
pub fn make_patches(&self, patch_log: &mut PatchLog) -> Vec<Patch> {
|
|
836
|
+
patch_log.make_patches(self)
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/// Get a set of [`Patch`]es which materialize the current state of the document
|
|
840
|
+
///
|
|
841
|
+
/// This is a convienence method for [`doc.diff(&[], current_heads)`][diff]
|
|
842
|
+
///
|
|
843
|
+
/// [diff]: Self::diff()
|
|
844
|
+
pub fn current_state(&self) -> Vec<Patch> {
|
|
845
|
+
let mut patch_log = PatchLog::active();
|
|
846
|
+
self.log_current_state(ObjMeta::root(), &mut patch_log, true);
|
|
847
|
+
patch_log.make_patches(self)
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/// Load an incremental save of a document.
|
|
851
|
+
///
|
|
852
|
+
/// Unlike [`Self::load()`] this imports changes into an existing document. It will work with
|
|
853
|
+
/// both the output of [`Self::save()`] and [`Self::save_after()`]
|
|
854
|
+
///
|
|
855
|
+
/// The return value is the number of ops which were applied, this is not useful and will
|
|
856
|
+
/// change in future.
|
|
857
|
+
pub fn load_incremental(&mut self, data: &[u8]) -> Result<usize, AutomergeError> {
|
|
858
|
+
self.load_incremental_log_patches(data, &mut PatchLog::inactive())
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/// Like [`Self::load_incremental()`] but log the changes to the current state of the document
|
|
862
|
+
/// to [`PatchLog`]
|
|
863
|
+
pub fn load_incremental_log_patches(
|
|
864
|
+
&mut self,
|
|
865
|
+
data: &[u8],
|
|
866
|
+
patch_log: &mut PatchLog,
|
|
867
|
+
) -> Result<usize, AutomergeError> {
|
|
868
|
+
if self.is_empty() {
|
|
869
|
+
let mut doc = Self::load_with_options(
|
|
870
|
+
data,
|
|
871
|
+
LoadOptions::new()
|
|
872
|
+
.on_partial_load(OnPartialLoad::Ignore)
|
|
873
|
+
.verification_mode(VerificationMode::Check),
|
|
874
|
+
)?;
|
|
875
|
+
doc = doc.with_actor(self.actor_id().clone());
|
|
876
|
+
if patch_log.is_active() {
|
|
877
|
+
doc.log_current_state(ObjMeta::root(), patch_log, true);
|
|
878
|
+
}
|
|
879
|
+
*self = doc;
|
|
880
|
+
return Ok(self.ops.len());
|
|
881
|
+
}
|
|
882
|
+
let changes = match load::load_changes(
|
|
883
|
+
storage::parse::Input::new(data),
|
|
884
|
+
self.text_encoding(),
|
|
885
|
+
&self.change_graph,
|
|
886
|
+
) {
|
|
887
|
+
load::LoadedChanges::Complete(c) => c,
|
|
888
|
+
load::LoadedChanges::Partial { error, loaded, .. } => {
|
|
889
|
+
tracing::warn!(successful_chunks=loaded.len(), err=?error, "partial load");
|
|
890
|
+
loaded
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
let start = self.ops.len();
|
|
894
|
+
self.apply_changes_log_patches(changes, patch_log)?;
|
|
895
|
+
let delta = self.ops.len() - start;
|
|
896
|
+
Ok(delta)
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
pub(crate) fn log_current_state(
|
|
900
|
+
&self,
|
|
901
|
+
obj: ObjMeta,
|
|
902
|
+
patch_log: &mut PatchLog,
|
|
903
|
+
recursive: bool,
|
|
904
|
+
) {
|
|
905
|
+
let clock = ClockRange::default();
|
|
906
|
+
let path_map = DiffIter::log(self, obj, clock, patch_log, recursive);
|
|
907
|
+
patch_log.path_hint(path_map);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
fn seq_for_actor(&self, actor: &ActorId) -> u64 {
|
|
911
|
+
self.ops
|
|
912
|
+
.lookup_actor(actor)
|
|
913
|
+
.map(|idx| self.change_graph.seq_for_actor(idx))
|
|
914
|
+
.unwrap_or(0)
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
pub(crate) fn has_actor_seq(&self, change: &Change) -> bool {
|
|
918
|
+
self.seq_for_actor(change.actor_id()) >= change.seq()
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/// Apply changes to this document.
|
|
922
|
+
///
|
|
923
|
+
/// This is idempotent in the sense that if a change has already been applied it will be
|
|
924
|
+
/// ignored.
|
|
925
|
+
pub fn apply_changes(
|
|
926
|
+
&mut self,
|
|
927
|
+
changes: impl IntoIterator<Item = Change> + Clone,
|
|
928
|
+
) -> Result<(), AutomergeError> {
|
|
929
|
+
self.apply_changes_log_patches(changes, &mut PatchLog::inactive())
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/// Like [`Self::apply_changes()`] but log the resulting changes to the current state of the
|
|
933
|
+
/// document to `patch_log`
|
|
934
|
+
pub fn apply_changes_log_patches<I: IntoIterator<Item = Change> + Clone>(
|
|
935
|
+
&mut self,
|
|
936
|
+
changes: I,
|
|
937
|
+
patch_log: &mut PatchLog,
|
|
938
|
+
) -> Result<(), AutomergeError> {
|
|
939
|
+
self.apply_changes_batch_log_patches(changes, patch_log)
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
/// Takes all the changes in `other` which are not in `self` and applies them
|
|
943
|
+
pub fn merge(&mut self, other: &mut Self) -> Result<Vec<ChangeHash>, AutomergeError> {
|
|
944
|
+
self.merge_and_log_patches(other, &mut PatchLog::inactive())
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/// Takes all the changes in `other` which are not in `self` and applies them whilst logging
|
|
948
|
+
/// the resulting changes to the current state of the document to `patch_log`
|
|
949
|
+
pub fn merge_and_log_patches(
|
|
950
|
+
&mut self,
|
|
951
|
+
other: &mut Self,
|
|
952
|
+
patch_log: &mut PatchLog,
|
|
953
|
+
) -> Result<Vec<ChangeHash>, AutomergeError> {
|
|
954
|
+
// TODO: Make this fallible and figure out how to do this transactionally
|
|
955
|
+
let changes = self.get_changes_added(other);
|
|
956
|
+
tracing::trace!(changes=?changes.iter().map(|c| c.hash()).collect::<Vec<_>>(), "merging new changes");
|
|
957
|
+
self.apply_changes_log_patches(changes, patch_log)?;
|
|
958
|
+
Ok(self.get_heads())
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/// EXPERIMENTAL: Write the set of changes in `hashes` to a "bundle"
|
|
962
|
+
///
|
|
963
|
+
/// A "bundle" is a compact representation of a set of changes which uses
|
|
964
|
+
/// the same compression tricks as the document encoding we use in
|
|
965
|
+
/// [`Automerge::save`].
|
|
966
|
+
///
|
|
967
|
+
/// This is an experimental API, the bundle format is still subject to change
|
|
968
|
+
/// and so should not be used in production just yet.
|
|
969
|
+
pub fn bundle<I>(&self, hashes: I) -> Result<Bundle, AutomergeError>
|
|
970
|
+
where
|
|
971
|
+
I: IntoIterator<Item = ChangeHash>,
|
|
972
|
+
{
|
|
973
|
+
Bundle::for_hashes(&self.ops, &self.change_graph, hashes)
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/// Save the entirety of this document in a compact form.
|
|
977
|
+
pub fn save_with_options(&self, options: SaveOptions) -> Vec<u8> {
|
|
978
|
+
self.assert_no_unused_actors(true);
|
|
979
|
+
|
|
980
|
+
let doc = Document::new(&self.ops, &self.change_graph, options.compress());
|
|
981
|
+
let mut bytes = doc.into_bytes();
|
|
982
|
+
|
|
983
|
+
if options.retain_orphans {
|
|
984
|
+
for orphaned in self.queue.iter() {
|
|
985
|
+
bytes.extend(orphaned.raw_bytes());
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
bytes
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
#[cfg(test)]
|
|
992
|
+
pub fn debug_cmp(&self, other: &Self) {
|
|
993
|
+
self.ops.debug_cmp(&other.ops);
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/// Save the entirety of this document in a compact form.
|
|
997
|
+
pub fn save(&self) -> Vec<u8> {
|
|
998
|
+
self.save_with_options(SaveOptions::default())
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/// Save the document and attempt to load it before returning - slow!
|
|
1002
|
+
pub fn save_and_verify(&self) -> Result<Vec<u8>, AutomergeError> {
|
|
1003
|
+
let bytes = self.save();
|
|
1004
|
+
Self::load(&bytes)?;
|
|
1005
|
+
Ok(bytes)
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/// Save this document, but don't run it through `DEFLATE` afterwards
|
|
1009
|
+
pub fn save_nocompress(&self) -> Vec<u8> {
|
|
1010
|
+
self.save_with_options(SaveOptions {
|
|
1011
|
+
deflate: false,
|
|
1012
|
+
..Default::default()
|
|
1013
|
+
})
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
/// Save the changes since the given heads
|
|
1017
|
+
///
|
|
1018
|
+
/// The output of this will not be a compressed document format, but a series of individual
|
|
1019
|
+
/// changes. This is useful if you know you have only made a small change since the last
|
|
1020
|
+
/// [`Self::save()`] and you want to immediately send it somewhere (e.g. you've inserted a
|
|
1021
|
+
/// single character in a text object).
|
|
1022
|
+
pub fn save_after(&self, heads: &[ChangeHash]) -> Vec<u8> {
|
|
1023
|
+
let changes = self.get_changes(heads);
|
|
1024
|
+
let mut bytes = vec![];
|
|
1025
|
+
for c in changes {
|
|
1026
|
+
bytes.extend(c.raw_bytes());
|
|
1027
|
+
}
|
|
1028
|
+
bytes
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
/// Filter the changes down to those that are not transitive dependencies of the heads.
|
|
1032
|
+
///
|
|
1033
|
+
/// Thus a graph with these heads has not seen the remaining changes.
|
|
1034
|
+
pub(crate) fn filter_changes(
|
|
1035
|
+
&self,
|
|
1036
|
+
heads: &[ChangeHash],
|
|
1037
|
+
changes: &mut BTreeSet<ChangeHash>,
|
|
1038
|
+
) -> Result<(), AutomergeError> {
|
|
1039
|
+
let heads = heads
|
|
1040
|
+
.iter()
|
|
1041
|
+
.filter(|hash| self.has_change(hash))
|
|
1042
|
+
.copied()
|
|
1043
|
+
.collect::<Vec<_>>();
|
|
1044
|
+
|
|
1045
|
+
self.change_graph.remove_ancestors(changes, &heads);
|
|
1046
|
+
|
|
1047
|
+
Ok(())
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/// Get the last change this actor made to the document.
|
|
1051
|
+
pub fn get_last_local_change(&self) -> Option<Change> {
|
|
1052
|
+
let actor = self.get_actor_index()?;
|
|
1053
|
+
let seq = self.change_graph.seq_for_actor(actor);
|
|
1054
|
+
let hash = self.change_graph.get_hash_for_actor_seq(actor, seq).ok()?;
|
|
1055
|
+
self.get_change_by_hash(&hash)
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
pub(crate) fn clock_range(&self, before: &[ChangeHash], after: &[ChangeHash]) -> ClockRange {
|
|
1059
|
+
let before = self.clock_at(before);
|
|
1060
|
+
let after = self.clock_at(after);
|
|
1061
|
+
ClockRange::Diff(before, after)
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
pub(crate) fn clock_at(&self, heads: &[ChangeHash]) -> Clock {
|
|
1065
|
+
self.change_graph.clock_for_heads(heads)
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
fn get_isolated_actor_index(&mut self, level: usize) -> usize {
|
|
1069
|
+
if level == 0 {
|
|
1070
|
+
self.get_or_create_actor_index()
|
|
1071
|
+
} else {
|
|
1072
|
+
let base_actor = self.get_actor();
|
|
1073
|
+
let new_actor = base_actor.with_concurrency(level);
|
|
1074
|
+
self.put_actor(new_actor)
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
pub(crate) fn isolate_actor(&mut self, heads: &[ChangeHash]) -> Isolation {
|
|
1079
|
+
let mut actor_index = self.get_isolated_actor_index(0);
|
|
1080
|
+
let mut clock = self.clock_at(heads);
|
|
1081
|
+
|
|
1082
|
+
for i in 1.. {
|
|
1083
|
+
let max_op = self.change_graph.max_op_for_actor(actor_index);
|
|
1084
|
+
if max_op == 0 || clock.covers(&OpId::new(max_op, actor_index)) {
|
|
1085
|
+
clock.isolate(actor_index);
|
|
1086
|
+
break;
|
|
1087
|
+
}
|
|
1088
|
+
actor_index = self.get_isolated_actor_index(i);
|
|
1089
|
+
clock = self.clock_at(heads); // need to recompute the clock b/c the actor indexes may have changed
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
let seq = self.change_graph.seq_for_actor(actor_index) + 1;
|
|
1093
|
+
|
|
1094
|
+
Isolation {
|
|
1095
|
+
actor_index,
|
|
1096
|
+
seq,
|
|
1097
|
+
clock,
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
fn get_hash(&self, actor: usize, seq: u64) -> Result<ChangeHash, AutomergeError> {
|
|
1102
|
+
self.change_graph.get_hash_for_actor_seq(actor, seq)
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
pub(crate) fn update_history(&mut self, change: &Change) {
|
|
1106
|
+
self.update_deps(change);
|
|
1107
|
+
|
|
1108
|
+
let actor_index = self
|
|
1109
|
+
.ops
|
|
1110
|
+
.actors
|
|
1111
|
+
.binary_search(change.actor_id())
|
|
1112
|
+
.expect("Change's actor not already in the document");
|
|
1113
|
+
|
|
1114
|
+
self.change_graph
|
|
1115
|
+
.add_change(change, actor_index)
|
|
1116
|
+
.expect("Change's deps should already be in the document");
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
fn insert_actor(&mut self, index: usize, actor: ActorId) -> usize {
|
|
1120
|
+
self.ops.insert_actor(index, actor);
|
|
1121
|
+
self.change_graph.insert_actor(index);
|
|
1122
|
+
self.actor.rewrite_with_new_actor(index);
|
|
1123
|
+
index
|
|
1124
|
+
}
|
|
1125
|
+
pub(crate) fn put_actor_ref(&mut self, actor: &ActorId) -> usize {
|
|
1126
|
+
match self.ops.actors.binary_search(actor) {
|
|
1127
|
+
Ok(idx) => idx,
|
|
1128
|
+
Err(idx) => self.insert_actor(idx, actor.clone()),
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
pub(crate) fn put_actor(&mut self, actor: ActorId) -> usize {
|
|
1133
|
+
match self.ops.actors.binary_search(&actor) {
|
|
1134
|
+
Ok(idx) => idx,
|
|
1135
|
+
Err(idx) => self.insert_actor(idx, actor),
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
fn update_deps(&mut self, change: &Change) {
|
|
1140
|
+
for d in change.deps() {
|
|
1141
|
+
self.deps.remove(d);
|
|
1142
|
+
}
|
|
1143
|
+
self.deps.insert(change.hash());
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
#[doc(hidden)]
|
|
1147
|
+
pub fn import(&self, s: &str) -> Result<(ExId, ObjType), AutomergeError> {
|
|
1148
|
+
let obj = self.import_obj(s)?;
|
|
1149
|
+
if obj == ExId::Root {
|
|
1150
|
+
Ok((ExId::Root, ObjType::Map))
|
|
1151
|
+
} else {
|
|
1152
|
+
let obj_type = self
|
|
1153
|
+
.object_type(&obj)
|
|
1154
|
+
.map_err(|_| AutomergeError::InvalidObjId(s.to_owned()))?;
|
|
1155
|
+
Ok((obj, obj_type))
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
#[doc(hidden)]
|
|
1160
|
+
pub fn import_obj(&self, s: &str) -> Result<ExId, AutomergeError> {
|
|
1161
|
+
if s == "_root" {
|
|
1162
|
+
Ok(ExId::Root)
|
|
1163
|
+
} else {
|
|
1164
|
+
let n = s
|
|
1165
|
+
.find('@')
|
|
1166
|
+
.ok_or_else(|| AutomergeError::InvalidObjIdFormat(s.to_owned()))?;
|
|
1167
|
+
let counter = s[0..n]
|
|
1168
|
+
.parse()
|
|
1169
|
+
.map_err(|_| AutomergeError::InvalidObjIdFormat(s.to_owned()))?;
|
|
1170
|
+
let actor = ActorId::from(hex::decode(&s[(n + 1)..]).unwrap());
|
|
1171
|
+
let actor = self
|
|
1172
|
+
.ops
|
|
1173
|
+
.lookup_actor(&actor)
|
|
1174
|
+
.ok_or_else(|| AutomergeError::InvalidObjId(s.to_owned()))?;
|
|
1175
|
+
let obj = ExId::Id(counter, self.ops.get_actor(actor).clone(), actor);
|
|
1176
|
+
Ok(obj)
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
pub fn dump(&self) {
|
|
1181
|
+
/*
|
|
1182
|
+
log!(
|
|
1183
|
+
" {:12} {:3} {:12} {:12} {:12} {:12} {:12}",
|
|
1184
|
+
"id",
|
|
1185
|
+
"ins",
|
|
1186
|
+
"obj",
|
|
1187
|
+
"key",
|
|
1188
|
+
"value",
|
|
1189
|
+
"pred",
|
|
1190
|
+
"succ"
|
|
1191
|
+
);
|
|
1192
|
+
*/
|
|
1193
|
+
self.ops.dump();
|
|
1194
|
+
/*
|
|
1195
|
+
for op in self.ops.iter() {
|
|
1196
|
+
let id = self.to_short_string(op.id);
|
|
1197
|
+
let obj = self.to_short_string(op.obj);
|
|
1198
|
+
let key = match op.key {
|
|
1199
|
+
KeyRef::Map(n) => n.to_owned(),
|
|
1200
|
+
KeyRef::Seq(n) => self.to_short_string(n),
|
|
1201
|
+
};
|
|
1202
|
+
let value: String = match op.op_type() {
|
|
1203
|
+
OpType::Put(value) => format!("{}", value),
|
|
1204
|
+
OpType::Make(obj) => format!("make({})", obj),
|
|
1205
|
+
OpType::Increment(obj) => format!("inc({})", obj),
|
|
1206
|
+
OpType::Delete => format!("del{}", 0),
|
|
1207
|
+
OpType::MarkBegin(_, MarkData { name, value }) => {
|
|
1208
|
+
format!("mark({},{})", name, value)
|
|
1209
|
+
}
|
|
1210
|
+
OpType::MarkEnd(_) => "/mark".to_string(),
|
|
1211
|
+
};
|
|
1212
|
+
//let pred: Vec<_> = op.pred().map(|id| self.to_short_string(id)).collect();
|
|
1213
|
+
let succ: Vec<_> = op.succ().map(|id| self.to_short_string(id)).collect();
|
|
1214
|
+
let insert = match op.insert {
|
|
1215
|
+
true => "t",
|
|
1216
|
+
false => "f",
|
|
1217
|
+
};
|
|
1218
|
+
log!(
|
|
1219
|
+
//" {:12} {:3} {:12} {:12} {:12} {:12?} {:12?}",
|
|
1220
|
+
" {:12} {:3} {:12} {:12} {:12} {:12?}",
|
|
1221
|
+
id,
|
|
1222
|
+
insert,
|
|
1223
|
+
obj,
|
|
1224
|
+
key,
|
|
1225
|
+
value,
|
|
1226
|
+
//pred,
|
|
1227
|
+
succ
|
|
1228
|
+
);
|
|
1229
|
+
}
|
|
1230
|
+
*/
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
/// Create patches representing the change in the current state of the document between the
|
|
1234
|
+
/// `before` and `after` heads. If the arguments are reverse it will observe the same changes
|
|
1235
|
+
/// in the opposite order.
|
|
1236
|
+
pub fn diff(&self, before_heads: &[ChangeHash], after_heads: &[ChangeHash]) -> Vec<Patch> {
|
|
1237
|
+
let clock = self.clock_range(before_heads, after_heads);
|
|
1238
|
+
let mut patch_log = PatchLog::active();
|
|
1239
|
+
DiffIter::log(self, ObjMeta::root(), clock, &mut patch_log, true);
|
|
1240
|
+
patch_log.heads = Some(after_heads.to_vec());
|
|
1241
|
+
patch_log.make_patches(self)
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
/// Create patches representing the change in the current state of an object
|
|
1245
|
+
/// in the document between the `before_heads` and `after_heads` heads. If
|
|
1246
|
+
/// the arguments are reverse it will observe the same changes in the
|
|
1247
|
+
/// opposite order.
|
|
1248
|
+
///
|
|
1249
|
+
/// # Arguments
|
|
1250
|
+
///
|
|
1251
|
+
/// * `obj` - The object to start the diff at.
|
|
1252
|
+
/// * `before_heads` - heads from [`Self::get_heads()`] at beginning point
|
|
1253
|
+
/// in the documents history
|
|
1254
|
+
/// * `after_heads` - heads from [`Self::get_heads()`] at ending point in
|
|
1255
|
+
/// the documents history.
|
|
1256
|
+
/// * `recursive` - if false, do not also diff child objects
|
|
1257
|
+
///
|
|
1258
|
+
/// Note: `before_heads` and `after_heads` do not have to be chronological.
|
|
1259
|
+
/// Document state can move backward.
|
|
1260
|
+
pub fn diff_obj(
|
|
1261
|
+
&self,
|
|
1262
|
+
obj: &ExId,
|
|
1263
|
+
before_heads: &[ChangeHash],
|
|
1264
|
+
after_heads: &[ChangeHash],
|
|
1265
|
+
recursive: bool,
|
|
1266
|
+
) -> Result<Vec<Patch>, AutomergeError> {
|
|
1267
|
+
let obj = self.exid_to_obj(obj.as_ref())?;
|
|
1268
|
+
let clock = self.clock_range(before_heads, after_heads);
|
|
1269
|
+
let mut patch_log = PatchLog::active();
|
|
1270
|
+
DiffIter::log(self, obj, clock, &mut patch_log, recursive);
|
|
1271
|
+
patch_log.heads = Some(after_heads.to_vec());
|
|
1272
|
+
Ok(patch_log.make_patches(self))
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
/// Get the heads of this document.
|
|
1276
|
+
pub fn get_heads(&self) -> Vec<ChangeHash> {
|
|
1277
|
+
let mut deps: Vec<_> = self.deps.iter().copied().collect();
|
|
1278
|
+
deps.sort_unstable();
|
|
1279
|
+
deps
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
pub fn get_changes(&self, have_deps: &[ChangeHash]) -> Vec<Change> {
|
|
1283
|
+
ChangeCollector::exclude_hashes(&self.ops, &self.change_graph, have_deps)
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
pub fn get_changes_meta(&self, have_deps: &[ChangeHash]) -> Vec<ChangeMetadata<'_>> {
|
|
1287
|
+
ChangeCollector::exclude_hashes_meta(&self.ops, &self.change_graph, have_deps)
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
pub fn get_change_meta_by_hash(&self, hash: &ChangeHash) -> Option<ChangeMetadata<'_>> {
|
|
1291
|
+
ChangeCollector::meta_for_hashes(&self.ops, &self.change_graph, [*hash])
|
|
1292
|
+
.ok()?
|
|
1293
|
+
.pop()
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
/// Get changes in `other` that are not in `self`
|
|
1297
|
+
pub fn get_changes_added(&self, other: &Self) -> Vec<Change> {
|
|
1298
|
+
// Depth-first traversal from the heads through the dependency graph,
|
|
1299
|
+
// until we reach a change that is already present in other
|
|
1300
|
+
let mut stack: Vec<_> = other.get_heads();
|
|
1301
|
+
tracing::trace!(their_heads=?stack, "finding changes to merge");
|
|
1302
|
+
let mut seen_hashes = HashSet::new();
|
|
1303
|
+
let mut added_change_hashes = Vec::new();
|
|
1304
|
+
while let Some(hash) = stack.pop() {
|
|
1305
|
+
if !seen_hashes.contains(&hash) && !self.has_change(&hash) {
|
|
1306
|
+
seen_hashes.insert(hash);
|
|
1307
|
+
added_change_hashes.push(hash);
|
|
1308
|
+
stack.extend(other.change_graph.deps_for_hash(&hash));
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
// Return those changes in the reverse of the order in which the depth-first search
|
|
1312
|
+
// found them. This is not necessarily a topological sort, but should usually be close.
|
|
1313
|
+
added_change_hashes.reverse();
|
|
1314
|
+
|
|
1315
|
+
// safe to unwrap here b/c added_changes all came from the change_graph
|
|
1316
|
+
other.get_changes_by_hashes(added_change_hashes).unwrap()
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
/// Get the hash of the change that contains the given `opid`.
|
|
1320
|
+
///
|
|
1321
|
+
/// Returns [`None`] if the `opid`:
|
|
1322
|
+
/// - is the root object id
|
|
1323
|
+
/// - does not exist in this document
|
|
1324
|
+
pub fn hash_for_opid(&self, exid: &ExId) -> Option<ChangeHash> {
|
|
1325
|
+
match exid {
|
|
1326
|
+
ExId::Root => None,
|
|
1327
|
+
ExId::Id(..) => {
|
|
1328
|
+
let opid = self.exid_to_opid(exid).ok()?;
|
|
1329
|
+
self.change_graph.opid_to_hash(opid)
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
fn calculate_marks(
|
|
1335
|
+
&self,
|
|
1336
|
+
obj: &ExId,
|
|
1337
|
+
clock: Option<Clock>,
|
|
1338
|
+
) -> Result<Vec<Mark>, AutomergeError> {
|
|
1339
|
+
let obj = self.exid_to_obj(obj.as_ref())?;
|
|
1340
|
+
let mut top_ops = self
|
|
1341
|
+
.ops()
|
|
1342
|
+
.iter_obj(&obj.id)
|
|
1343
|
+
.visible_slow(clock)
|
|
1344
|
+
.top_ops()
|
|
1345
|
+
.marks();
|
|
1346
|
+
|
|
1347
|
+
let Some(seq_type) = obj.typ.as_sequence_type() else {
|
|
1348
|
+
// Really we should return an error here but we don't in order to stay
|
|
1349
|
+
// compatibile with older implementations
|
|
1350
|
+
return Ok(Vec::new());
|
|
1351
|
+
};
|
|
1352
|
+
|
|
1353
|
+
let mut index = 0;
|
|
1354
|
+
let mut acc = MarkAccumulator::default();
|
|
1355
|
+
let mut last_marks = None;
|
|
1356
|
+
let mut mark_len = 0;
|
|
1357
|
+
let mut mark_index = 0;
|
|
1358
|
+
while let Some(o) = top_ops.next() {
|
|
1359
|
+
let marks = top_ops.get_marks();
|
|
1360
|
+
let len = o.width(seq_type, self.text_encoding());
|
|
1361
|
+
if last_marks.as_ref() != marks {
|
|
1362
|
+
match last_marks.as_ref() {
|
|
1363
|
+
Some(m) if mark_len > 0 => acc.add(mark_index, mark_len, m),
|
|
1364
|
+
_ => (),
|
|
1365
|
+
}
|
|
1366
|
+
last_marks = marks.cloned();
|
|
1367
|
+
mark_index = index;
|
|
1368
|
+
mark_len = 0;
|
|
1369
|
+
}
|
|
1370
|
+
mark_len += len;
|
|
1371
|
+
index += len;
|
|
1372
|
+
}
|
|
1373
|
+
match last_marks.as_ref() {
|
|
1374
|
+
Some(m) if mark_len > 0 => acc.add(mark_index, mark_len, m),
|
|
1375
|
+
_ => (),
|
|
1376
|
+
}
|
|
1377
|
+
Ok(acc.into_iter_no_unmark().collect())
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
pub fn hydrate(&self, heads: Option<&[ChangeHash]>) -> hydrate::Value {
|
|
1381
|
+
let clock = heads.map(|heads| self.clock_at(heads));
|
|
1382
|
+
self.hydrate_map(&ObjId::root(), clock.as_ref())
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
pub(crate) fn hydrate_obj(
|
|
1386
|
+
&self,
|
|
1387
|
+
obj: &crate::ObjId,
|
|
1388
|
+
heads: Option<&[ChangeHash]>,
|
|
1389
|
+
) -> Result<hydrate::Value, AutomergeError> {
|
|
1390
|
+
let obj = self.exid_to_obj(obj)?;
|
|
1391
|
+
let clock = heads.map(|heads| self.clock_at(heads));
|
|
1392
|
+
Ok(match obj.typ {
|
|
1393
|
+
ObjType::Map | ObjType::Table => self.hydrate_map(&obj.id, clock.as_ref()),
|
|
1394
|
+
ObjType::List => self.hydrate_list(&obj.id, clock.as_ref()),
|
|
1395
|
+
ObjType::Text => self.hydrate_text(&obj.id, clock.as_ref()),
|
|
1396
|
+
})
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
pub(crate) fn parents_for(
|
|
1400
|
+
&self,
|
|
1401
|
+
obj: &ExId,
|
|
1402
|
+
clock: Option<Clock>,
|
|
1403
|
+
) -> Result<Parents<'_>, AutomergeError> {
|
|
1404
|
+
let obj = self.exid_to_obj(obj)?;
|
|
1405
|
+
// FIXME - now that we have blocks a correct text_rep is relevent
|
|
1406
|
+
Ok(self.ops.parents(obj.id, clock))
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
pub(crate) fn keys_for(&self, obj: &ExId, clock: Option<Clock>) -> Keys<'_> {
|
|
1410
|
+
self.exid_to_obj(obj)
|
|
1411
|
+
.ok()
|
|
1412
|
+
.map(|obj| self.ops.keys(&obj.id, clock))
|
|
1413
|
+
.unwrap_or_default()
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
pub(crate) fn iter_for(&self, obj: &ExId, clock: Option<Clock>) -> DocIter<'_> {
|
|
1417
|
+
self.exid_to_obj(obj)
|
|
1418
|
+
.ok()
|
|
1419
|
+
.map(|obj| DocIter::new(self, obj, clock))
|
|
1420
|
+
.unwrap_or_else(|| DocIter::empty(self.text_encoding()))
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
pub(crate) fn map_range_for<'a, R: RangeBounds<String> + 'a>(
|
|
1424
|
+
&'a self,
|
|
1425
|
+
obj: &ExId,
|
|
1426
|
+
range: R,
|
|
1427
|
+
clock: Option<Clock>,
|
|
1428
|
+
) -> MapRange<'a> {
|
|
1429
|
+
self.exid_to_obj(obj)
|
|
1430
|
+
.ok()
|
|
1431
|
+
.map(|obj| self.ops.map_range(&obj.id, range, clock))
|
|
1432
|
+
.unwrap_or_default()
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
pub(crate) fn list_range_for<R: RangeBounds<usize>>(
|
|
1436
|
+
&self,
|
|
1437
|
+
obj: &ExId,
|
|
1438
|
+
range: R,
|
|
1439
|
+
clock: Option<Clock>,
|
|
1440
|
+
) -> ListRange<'_> {
|
|
1441
|
+
self.exid_to_obj(obj)
|
|
1442
|
+
.ok()
|
|
1443
|
+
.map(|obj| self.ops.list_range(&obj.id, range, clock))
|
|
1444
|
+
.unwrap_or_default()
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
pub(crate) fn values_for(&self, obj: &ExId, clock: Option<Clock>) -> Values<'_> {
|
|
1448
|
+
self.exid_to_obj(obj)
|
|
1449
|
+
.ok()
|
|
1450
|
+
.map(|obj| Values::new(&self.ops, self.ops.top_ops(&obj.id, clock.clone()), clock))
|
|
1451
|
+
.unwrap_or_default()
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
pub(crate) fn length_for(&self, obj: &ExId, clock: Option<Clock>) -> usize {
|
|
1455
|
+
// FIXME - is doc.length() for a text always the string length?
|
|
1456
|
+
self.exid_to_obj(obj)
|
|
1457
|
+
.map(|obj| self.ops.seq_length(&obj.id, self.text_encoding(), clock))
|
|
1458
|
+
.unwrap_or(0)
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
pub(crate) fn text_for(
|
|
1462
|
+
&self,
|
|
1463
|
+
obj: &ExId,
|
|
1464
|
+
clock: Option<Clock>,
|
|
1465
|
+
) -> Result<String, AutomergeError> {
|
|
1466
|
+
let obj = self.exid_to_obj(obj)?;
|
|
1467
|
+
Ok(self.ops.text(&obj.id, clock))
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
pub(crate) fn spans_for(
|
|
1471
|
+
&self,
|
|
1472
|
+
obj: &ExId,
|
|
1473
|
+
clock: Option<Clock>,
|
|
1474
|
+
) -> Result<Spans<'_>, AutomergeError> {
|
|
1475
|
+
let obj = self.exid_to_obj(obj)?;
|
|
1476
|
+
Ok(Spans::new(self.ops.spans(&obj.id, clock)))
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
pub(crate) fn get_cursor_for(
|
|
1480
|
+
&self,
|
|
1481
|
+
obj: &ExId,
|
|
1482
|
+
position: CursorPosition,
|
|
1483
|
+
clock: Option<Clock>,
|
|
1484
|
+
move_cursor: MoveCursor,
|
|
1485
|
+
) -> Result<Cursor, AutomergeError> {
|
|
1486
|
+
let obj = self.exid_to_obj(obj)?;
|
|
1487
|
+
let Some(seq_type) = obj.typ.as_sequence_type() else {
|
|
1488
|
+
return Err(AutomergeError::InvalidOp(obj.typ));
|
|
1489
|
+
};
|
|
1490
|
+
match position {
|
|
1491
|
+
CursorPosition::Start => Ok(Cursor::Start),
|
|
1492
|
+
CursorPosition::End => Ok(Cursor::End),
|
|
1493
|
+
CursorPosition::Index(i) => {
|
|
1494
|
+
let found = self
|
|
1495
|
+
.ops
|
|
1496
|
+
.seek_ops_by_index(&obj.id, i, seq_type, clock.as_ref());
|
|
1497
|
+
|
|
1498
|
+
if let Some(op) = found.ops.last() {
|
|
1499
|
+
Ok(Cursor::Op(OpCursor::new(op.id, &self.ops, move_cursor)))
|
|
1500
|
+
} else {
|
|
1501
|
+
Err(AutomergeError::InvalidIndex(i))
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
pub(crate) fn get_cursor_position_for(
|
|
1508
|
+
&self,
|
|
1509
|
+
obj: &ExId,
|
|
1510
|
+
cursor: &Cursor,
|
|
1511
|
+
clock: Option<Clock>,
|
|
1512
|
+
) -> Result<usize, AutomergeError> {
|
|
1513
|
+
match cursor {
|
|
1514
|
+
Cursor::Start => Ok(0),
|
|
1515
|
+
Cursor::End => Ok(self.length_for(obj, clock)),
|
|
1516
|
+
Cursor::Op(op) => {
|
|
1517
|
+
let obj_meta = self.exid_to_obj(obj)?;
|
|
1518
|
+
|
|
1519
|
+
let Some(seq_type) = obj_meta.typ.as_sequence_type() else {
|
|
1520
|
+
return Err(AutomergeError::InvalidCursor(cursor.clone()));
|
|
1521
|
+
};
|
|
1522
|
+
|
|
1523
|
+
let opid = self.op_cursor_to_opid(op, clock.as_ref())?;
|
|
1524
|
+
|
|
1525
|
+
let found = self
|
|
1526
|
+
.ops
|
|
1527
|
+
.seek_list_opid(&obj_meta.id, opid, seq_type, clock.as_ref())
|
|
1528
|
+
.ok_or_else(|| AutomergeError::InvalidCursor(cursor.clone()))?;
|
|
1529
|
+
|
|
1530
|
+
match op.move_cursor {
|
|
1531
|
+
// `MoveCursor::After` mimics the original behavior of cursors.
|
|
1532
|
+
//
|
|
1533
|
+
// The original behavior was to just return the `FoundOpId::index` found by
|
|
1534
|
+
// `OpSetInternal::seek_list_opid()`.
|
|
1535
|
+
//
|
|
1536
|
+
// This index always corresponds to the:
|
|
1537
|
+
// - index of the item itself (if it's visible at `clock`)
|
|
1538
|
+
// - next index of visible item that **was also visible at the time of cursor creation**
|
|
1539
|
+
// (if the item is not visible at `clock`).
|
|
1540
|
+
// - or `sequence.length` if none of the next items are visible at `clock`.
|
|
1541
|
+
MoveCursor::After => Ok(found.index),
|
|
1542
|
+
MoveCursor::Before => {
|
|
1543
|
+
// `MoveCursor::Before` behaves like `MoveCursor::After` but in the opposite direction:
|
|
1544
|
+
//
|
|
1545
|
+
// - if the item is visible at `clock`, just return its index
|
|
1546
|
+
// - if the item isn't visible at `clock`, find the index of the **previous** item
|
|
1547
|
+
// that's visible at `clock` that was also visible at the time of cursor creation.
|
|
1548
|
+
// - if none of the previous items are visible (or the index of the original item is 0),
|
|
1549
|
+
// our index is `0`.
|
|
1550
|
+
if found.visible || found.index == 0 {
|
|
1551
|
+
Ok(found.index)
|
|
1552
|
+
} else {
|
|
1553
|
+
// FIXME: this should probably be an `OpSet` query
|
|
1554
|
+
// also this implementation is likely very inefficient
|
|
1555
|
+
|
|
1556
|
+
// current implementation walks upwards through `key` of op pointed to by cursor
|
|
1557
|
+
// and checks if `key` is visible by using `seek_list_opid()`.
|
|
1558
|
+
|
|
1559
|
+
let mut key = found
|
|
1560
|
+
.op.key.elemid()
|
|
1561
|
+
.expect("failed to retrieve initial cursor op key for MoveCursor::Before")
|
|
1562
|
+
.0;
|
|
1563
|
+
|
|
1564
|
+
loop {
|
|
1565
|
+
let f = self.ops.seek_list_opid(
|
|
1566
|
+
&obj_meta.id,
|
|
1567
|
+
key,
|
|
1568
|
+
seq_type,
|
|
1569
|
+
clock.as_ref(),
|
|
1570
|
+
);
|
|
1571
|
+
|
|
1572
|
+
match f {
|
|
1573
|
+
Some(f) => {
|
|
1574
|
+
if f.visible {
|
|
1575
|
+
return Ok(f.index);
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
key = f
|
|
1579
|
+
.op
|
|
1580
|
+
.key
|
|
1581
|
+
.elemid()
|
|
1582
|
+
.expect(
|
|
1583
|
+
"failed to retrieve op key in MoveCursor::Before",
|
|
1584
|
+
)
|
|
1585
|
+
.0;
|
|
1586
|
+
}
|
|
1587
|
+
// reached when we've gone before the beginning of the sequence
|
|
1588
|
+
None => break Ok(0),
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
pub(crate) fn marks_for(
|
|
1599
|
+
&self,
|
|
1600
|
+
obj: &ExId,
|
|
1601
|
+
clock: Option<Clock>,
|
|
1602
|
+
) -> Result<Vec<Mark>, AutomergeError> {
|
|
1603
|
+
self.calculate_marks(obj, clock)
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
pub(crate) fn get_for(
|
|
1607
|
+
&self,
|
|
1608
|
+
obj: &ExId,
|
|
1609
|
+
prop: Prop,
|
|
1610
|
+
clock: Option<Clock>,
|
|
1611
|
+
) -> Result<Option<(Value<'_>, ExId)>, AutomergeError> {
|
|
1612
|
+
let obj = self.exid_to_obj(obj)?;
|
|
1613
|
+
let op = match (obj.typ, prop) {
|
|
1614
|
+
(ObjType::Map | ObjType::Table, Prop::Map(key)) => self
|
|
1615
|
+
.ops
|
|
1616
|
+
.seek_ops_by_map_key(&obj.id, &key, clock.as_ref())
|
|
1617
|
+
.ops
|
|
1618
|
+
.into_iter()
|
|
1619
|
+
.next_back()
|
|
1620
|
+
.map(|op| op.tagged_value(self.ops())),
|
|
1621
|
+
(ObjType::List | ObjType::Text, Prop::Seq(i)) => {
|
|
1622
|
+
let seq_type = obj
|
|
1623
|
+
.typ
|
|
1624
|
+
.as_sequence_type()
|
|
1625
|
+
.expect("list and text must have a sequence type");
|
|
1626
|
+
self.ops
|
|
1627
|
+
.seek_ops_by_index(&obj.id, i, seq_type, clock.as_ref())
|
|
1628
|
+
.ops
|
|
1629
|
+
.into_iter()
|
|
1630
|
+
.next_back()
|
|
1631
|
+
.map(|op| op.tagged_value(self.ops()))
|
|
1632
|
+
}
|
|
1633
|
+
_ => return Err(AutomergeError::InvalidOp(obj.typ)),
|
|
1634
|
+
};
|
|
1635
|
+
Ok(op)
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
pub(crate) fn get_all_for<O: AsRef<ExId>, P: Into<Prop>>(
|
|
1639
|
+
&self,
|
|
1640
|
+
obj: O,
|
|
1641
|
+
prop: P,
|
|
1642
|
+
clock: Option<Clock>,
|
|
1643
|
+
) -> Result<Vec<(Value<'_>, ExId)>, AutomergeError> {
|
|
1644
|
+
let prop = prop.into();
|
|
1645
|
+
let obj = self.exid_to_obj(obj.as_ref())?;
|
|
1646
|
+
let values = match (obj.typ, prop) {
|
|
1647
|
+
(ObjType::Map | ObjType::Table, Prop::Map(key)) => self
|
|
1648
|
+
.ops
|
|
1649
|
+
.seek_ops_by_map_key(&obj.id, &key, clock.as_ref())
|
|
1650
|
+
.ops
|
|
1651
|
+
.into_iter()
|
|
1652
|
+
.map(|op| op.tagged_value(self.ops()))
|
|
1653
|
+
.collect::<Vec<_>>(),
|
|
1654
|
+
(ObjType::List | ObjType::Text, Prop::Seq(i)) => {
|
|
1655
|
+
let seq_type = obj
|
|
1656
|
+
.typ
|
|
1657
|
+
.as_sequence_type()
|
|
1658
|
+
.expect("list and text must have a sequence type");
|
|
1659
|
+
self.ops
|
|
1660
|
+
.seek_ops_by_index(&obj.id, i, seq_type, clock.as_ref())
|
|
1661
|
+
.ops
|
|
1662
|
+
.into_iter()
|
|
1663
|
+
.map(|op| op.tagged_value(self.ops()))
|
|
1664
|
+
.collect::<Vec<_>>()
|
|
1665
|
+
}
|
|
1666
|
+
_ => return Err(AutomergeError::InvalidOp(obj.typ)),
|
|
1667
|
+
};
|
|
1668
|
+
// this is a test to make sure opid and exid are always sorting the same way
|
|
1669
|
+
assert_eq!(
|
|
1670
|
+
values.iter().map(|v| &v.1).collect::<Vec<_>>(),
|
|
1671
|
+
values.iter().map(|v| &v.1).sorted().collect::<Vec<_>>()
|
|
1672
|
+
);
|
|
1673
|
+
Ok(values)
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
pub(crate) fn get_marks_for<O: AsRef<ExId>>(
|
|
1677
|
+
&self,
|
|
1678
|
+
obj: O,
|
|
1679
|
+
index: usize,
|
|
1680
|
+
clock: Option<Clock>,
|
|
1681
|
+
) -> Result<MarkSet, AutomergeError> {
|
|
1682
|
+
let obj = self.exid_to_obj(obj.as_ref())?;
|
|
1683
|
+
let mut iter = self
|
|
1684
|
+
.ops
|
|
1685
|
+
.iter_obj(&obj.id)
|
|
1686
|
+
.visible_slow(clock)
|
|
1687
|
+
.top_ops()
|
|
1688
|
+
.marks();
|
|
1689
|
+
iter.nth(index);
|
|
1690
|
+
match iter.get_marks() {
|
|
1691
|
+
Some(arc) => Ok(arc.as_ref().clone().without_unmarks()),
|
|
1692
|
+
None => Ok(MarkSet::default()),
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
fn convert_scalar_strings_to_text(&mut self) -> Result<(), AutomergeError> {
|
|
1697
|
+
struct Conversion {
|
|
1698
|
+
obj_id: ExId,
|
|
1699
|
+
prop: Prop,
|
|
1700
|
+
text: smol_str::SmolStr,
|
|
1701
|
+
}
|
|
1702
|
+
let mut to_convert = Vec::new();
|
|
1703
|
+
for (obj, ops) in self.ops.iter_objs() {
|
|
1704
|
+
match obj.typ {
|
|
1705
|
+
ObjType::Map | ObjType::List => {
|
|
1706
|
+
for op in ops.visible_slow(None) {
|
|
1707
|
+
//if !op.visible() {
|
|
1708
|
+
// continue;
|
|
1709
|
+
//}
|
|
1710
|
+
if let OpType::Put(ScalarValue::Str(s)) = op.op_type() {
|
|
1711
|
+
let prop = match op.key {
|
|
1712
|
+
KeyRef::Map(prop) => Prop::Map(prop.into()),
|
|
1713
|
+
KeyRef::Seq(_) => {
|
|
1714
|
+
let Some(found) = self.ops.seek_list_opid(
|
|
1715
|
+
&obj.id,
|
|
1716
|
+
op.id,
|
|
1717
|
+
SequenceType::List,
|
|
1718
|
+
None,
|
|
1719
|
+
) else {
|
|
1720
|
+
continue;
|
|
1721
|
+
};
|
|
1722
|
+
Prop::Seq(found.index)
|
|
1723
|
+
}
|
|
1724
|
+
};
|
|
1725
|
+
to_convert.push(Conversion {
|
|
1726
|
+
obj_id: self.ops.id_to_exid(obj.id.0),
|
|
1727
|
+
prop,
|
|
1728
|
+
text: smol_str::SmolStr::from(s),
|
|
1729
|
+
})
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
_ => {}
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
if !to_convert.is_empty() {
|
|
1738
|
+
let mut tx = self.transaction();
|
|
1739
|
+
for Conversion { obj_id, prop, text } in to_convert {
|
|
1740
|
+
let text_id = tx.put_object(obj_id, prop, ObjType::Text)?;
|
|
1741
|
+
tx.splice_text(&text_id, 0, 0, &text)?;
|
|
1742
|
+
}
|
|
1743
|
+
tx.commit();
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
Ok(())
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
/// Whether the peer represented by `other` has all the changes we have
|
|
1750
|
+
pub fn has_our_changes(&self, other: &crate::sync::State) -> bool {
|
|
1751
|
+
other.shared_heads == self.get_heads()
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
pub(crate) fn has_change(&self, head: &ChangeHash) -> bool {
|
|
1755
|
+
self.change_graph.has_change(head)
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
pub fn text_encoding(&self) -> TextEncoding {
|
|
1759
|
+
self.ops.text_encoding
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
impl ReadDoc for Automerge {
|
|
1764
|
+
fn parents<O: AsRef<ExId>>(&self, obj: O) -> Result<Parents<'_>, AutomergeError> {
|
|
1765
|
+
self.parents_for(obj.as_ref(), None)
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
fn parents_at<O: AsRef<ExId>>(
|
|
1769
|
+
&self,
|
|
1770
|
+
obj: O,
|
|
1771
|
+
heads: &[ChangeHash],
|
|
1772
|
+
) -> Result<Parents<'_>, AutomergeError> {
|
|
1773
|
+
let clock = self.clock_at(heads);
|
|
1774
|
+
self.parents_for(obj.as_ref(), Some(clock))
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
fn keys<O: AsRef<ExId>>(&self, obj: O) -> Keys<'_> {
|
|
1778
|
+
self.keys_for(obj.as_ref(), None)
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
fn keys_at<O: AsRef<ExId>>(&self, obj: O, heads: &[ChangeHash]) -> Keys<'_> {
|
|
1782
|
+
let clock = self.clock_at(heads);
|
|
1783
|
+
self.keys_for(obj.as_ref(), Some(clock))
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
fn iter_at<O: AsRef<ExId>>(&self, obj: O, heads: Option<&[ChangeHash]>) -> DocIter<'_> {
|
|
1787
|
+
//let obj = self.exid_to_obj(obj.as_ref()).unwrap();
|
|
1788
|
+
let clock = heads.map(|heads| self.clock_at(heads));
|
|
1789
|
+
self.iter_for(obj.as_ref(), clock)
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
fn map_range<'a, O: AsRef<ExId>, R: RangeBounds<String> + 'a>(
|
|
1793
|
+
&'a self,
|
|
1794
|
+
obj: O,
|
|
1795
|
+
range: R,
|
|
1796
|
+
) -> MapRange<'a> {
|
|
1797
|
+
self.map_range_for(obj.as_ref(), range, None)
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
fn map_range_at<'a, O: AsRef<ExId>, R: RangeBounds<String> + 'a>(
|
|
1801
|
+
&'a self,
|
|
1802
|
+
obj: O,
|
|
1803
|
+
range: R,
|
|
1804
|
+
heads: &[ChangeHash],
|
|
1805
|
+
) -> MapRange<'a> {
|
|
1806
|
+
let clock = self.clock_at(heads);
|
|
1807
|
+
self.map_range_for(obj.as_ref(), range, Some(clock))
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
fn list_range<O: AsRef<ExId>, R: RangeBounds<usize>>(&self, obj: O, range: R) -> ListRange<'_> {
|
|
1811
|
+
self.list_range_for(obj.as_ref(), range, None)
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
fn list_range_at<O: AsRef<ExId>, R: RangeBounds<usize>>(
|
|
1815
|
+
&self,
|
|
1816
|
+
obj: O,
|
|
1817
|
+
range: R,
|
|
1818
|
+
heads: &[ChangeHash],
|
|
1819
|
+
) -> ListRange<'_> {
|
|
1820
|
+
let clock = self.clock_at(heads);
|
|
1821
|
+
self.list_range_for(obj.as_ref(), range, Some(clock))
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
fn values<O: AsRef<ExId>>(&self, obj: O) -> Values<'_> {
|
|
1825
|
+
self.values_for(obj.as_ref(), None)
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
fn values_at<O: AsRef<ExId>>(&self, obj: O, heads: &[ChangeHash]) -> Values<'_> {
|
|
1829
|
+
let clock = self.clock_at(heads);
|
|
1830
|
+
self.values_for(obj.as_ref(), Some(clock))
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
fn length<O: AsRef<ExId>>(&self, obj: O) -> usize {
|
|
1834
|
+
self.length_for(obj.as_ref(), None)
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
fn length_at<O: AsRef<ExId>>(&self, obj: O, heads: &[ChangeHash]) -> usize {
|
|
1838
|
+
let clock = self.clock_at(heads);
|
|
1839
|
+
self.length_for(obj.as_ref(), Some(clock))
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
fn text<O: AsRef<ExId>>(&self, obj: O) -> Result<String, AutomergeError> {
|
|
1843
|
+
self.text_for(obj.as_ref(), None)
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
fn spans<O: AsRef<ExId>>(&self, obj: O) -> Result<Spans<'_>, AutomergeError> {
|
|
1847
|
+
self.spans_for(obj.as_ref(), None)
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
fn spans_at<O: AsRef<ExId>>(
|
|
1851
|
+
&self,
|
|
1852
|
+
obj: O,
|
|
1853
|
+
heads: &[ChangeHash],
|
|
1854
|
+
) -> Result<Spans<'_>, AutomergeError> {
|
|
1855
|
+
let clock = self.clock_at(heads);
|
|
1856
|
+
self.spans_for(obj.as_ref(), Some(clock))
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
fn get_cursor<O: AsRef<ExId>, I: Into<CursorPosition>>(
|
|
1860
|
+
&self,
|
|
1861
|
+
obj: O,
|
|
1862
|
+
position: I,
|
|
1863
|
+
at: Option<&[ChangeHash]>,
|
|
1864
|
+
) -> Result<Cursor, AutomergeError> {
|
|
1865
|
+
let clock = at.map(|heads| self.clock_at(heads));
|
|
1866
|
+
self.get_cursor_for(obj.as_ref(), position.into(), clock, MoveCursor::After)
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
fn get_cursor_moving<O: AsRef<ExId>, I: Into<CursorPosition>>(
|
|
1870
|
+
&self,
|
|
1871
|
+
obj: O,
|
|
1872
|
+
position: I,
|
|
1873
|
+
at: Option<&[ChangeHash]>,
|
|
1874
|
+
move_cursor: MoveCursor,
|
|
1875
|
+
) -> Result<Cursor, AutomergeError> {
|
|
1876
|
+
let clock = at.map(|heads| self.clock_at(heads));
|
|
1877
|
+
self.get_cursor_for(obj.as_ref(), position.into(), clock, move_cursor)
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
fn get_cursor_position<O: AsRef<ExId>>(
|
|
1881
|
+
&self,
|
|
1882
|
+
obj: O,
|
|
1883
|
+
cursor: &Cursor,
|
|
1884
|
+
at: Option<&[ChangeHash]>,
|
|
1885
|
+
) -> Result<usize, AutomergeError> {
|
|
1886
|
+
let clock = at.map(|heads| self.clock_at(heads));
|
|
1887
|
+
self.get_cursor_position_for(obj.as_ref(), cursor, clock)
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
fn text_at<O: AsRef<ExId>>(
|
|
1891
|
+
&self,
|
|
1892
|
+
obj: O,
|
|
1893
|
+
heads: &[ChangeHash],
|
|
1894
|
+
) -> Result<String, AutomergeError> {
|
|
1895
|
+
let clock = self.clock_at(heads);
|
|
1896
|
+
self.text_for(obj.as_ref(), Some(clock))
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
fn marks<O: AsRef<ExId>>(&self, obj: O) -> Result<Vec<Mark>, AutomergeError> {
|
|
1900
|
+
self.marks_for(obj.as_ref(), None)
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
fn marks_at<O: AsRef<ExId>>(
|
|
1904
|
+
&self,
|
|
1905
|
+
obj: O,
|
|
1906
|
+
heads: &[ChangeHash],
|
|
1907
|
+
) -> Result<Vec<Mark>, AutomergeError> {
|
|
1908
|
+
let clock = self.clock_at(heads);
|
|
1909
|
+
self.marks_for(obj.as_ref(), Some(clock))
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
fn hydrate<O: AsRef<ExId>>(
|
|
1913
|
+
&self,
|
|
1914
|
+
obj: O,
|
|
1915
|
+
heads: Option<&[ChangeHash]>,
|
|
1916
|
+
) -> Result<hydrate::Value, AutomergeError> {
|
|
1917
|
+
let obj = self.exid_to_obj(obj.as_ref())?;
|
|
1918
|
+
let clock = heads.map(|h| self.clock_at(h));
|
|
1919
|
+
Ok(match obj.typ {
|
|
1920
|
+
ObjType::List => self.hydrate_list(&obj.id, clock.as_ref()),
|
|
1921
|
+
ObjType::Text => self.hydrate_text(&obj.id, clock.as_ref()),
|
|
1922
|
+
_ => self.hydrate_map(&obj.id, clock.as_ref()),
|
|
1923
|
+
})
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
fn get_marks<O: AsRef<ExId>>(
|
|
1927
|
+
&self,
|
|
1928
|
+
obj: O,
|
|
1929
|
+
index: usize,
|
|
1930
|
+
heads: Option<&[ChangeHash]>,
|
|
1931
|
+
) -> Result<MarkSet, AutomergeError> {
|
|
1932
|
+
let clock = heads.map(|h| self.clock_at(h));
|
|
1933
|
+
self.get_marks_for(obj.as_ref(), index, clock)
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
fn get<O: AsRef<ExId>, P: Into<Prop>>(
|
|
1937
|
+
&self,
|
|
1938
|
+
obj: O,
|
|
1939
|
+
prop: P,
|
|
1940
|
+
) -> Result<Option<(Value<'_>, ExId)>, AutomergeError> {
|
|
1941
|
+
self.get_for(obj.as_ref(), prop.into(), None)
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
fn get_at<O: AsRef<ExId>, P: Into<Prop>>(
|
|
1945
|
+
&self,
|
|
1946
|
+
obj: O,
|
|
1947
|
+
prop: P,
|
|
1948
|
+
heads: &[ChangeHash],
|
|
1949
|
+
) -> Result<Option<(Value<'_>, ExId)>, AutomergeError> {
|
|
1950
|
+
let clock = Some(self.clock_at(heads));
|
|
1951
|
+
self.get_for(obj.as_ref(), prop.into(), clock)
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
fn get_all<O: AsRef<ExId>, P: Into<Prop>>(
|
|
1955
|
+
&self,
|
|
1956
|
+
obj: O,
|
|
1957
|
+
prop: P,
|
|
1958
|
+
) -> Result<Vec<(Value<'_>, ExId)>, AutomergeError> {
|
|
1959
|
+
self.get_all_for(obj.as_ref(), prop.into(), None)
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
fn get_all_at<O: AsRef<ExId>, P: Into<Prop>>(
|
|
1963
|
+
&self,
|
|
1964
|
+
obj: O,
|
|
1965
|
+
prop: P,
|
|
1966
|
+
heads: &[ChangeHash],
|
|
1967
|
+
) -> Result<Vec<(Value<'_>, ExId)>, AutomergeError> {
|
|
1968
|
+
let clock = Some(self.clock_at(heads));
|
|
1969
|
+
self.get_all_for(obj.as_ref(), prop.into(), clock)
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
fn object_type<O: AsRef<ExId>>(&self, obj: O) -> Result<ObjType, AutomergeError> {
|
|
1973
|
+
let obj = obj.as_ref();
|
|
1974
|
+
let opid = self.exid_to_opid(obj)?;
|
|
1975
|
+
let typ = self.ops.object_type(&ObjId(opid));
|
|
1976
|
+
typ.ok_or_else(|| AutomergeError::InvalidObjId(obj.to_string()))
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
#[inline(never)]
|
|
1980
|
+
fn get_missing_deps(&self, heads: &[ChangeHash]) -> Vec<ChangeHash> {
|
|
1981
|
+
let mut missing = HashSet::new();
|
|
1982
|
+
|
|
1983
|
+
for head in self.queue.iter().flat_map(|change| change.deps()) {
|
|
1984
|
+
if !self.has_change(head) {
|
|
1985
|
+
missing.insert(head);
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
for head in heads {
|
|
1990
|
+
if !self.has_change(head) {
|
|
1991
|
+
missing.insert(head);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
let mut missing = missing
|
|
1996
|
+
.into_iter()
|
|
1997
|
+
.filter(|hash| !self.queue.has_hash(hash))
|
|
1998
|
+
.copied()
|
|
1999
|
+
.collect::<Vec<_>>();
|
|
2000
|
+
missing.sort();
|
|
2001
|
+
missing
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
fn get_change_by_hash(&self, hash: &ChangeHash) -> Option<Change> {
|
|
2005
|
+
ChangeCollector::for_hashes(&self.ops, &self.change_graph, [*hash])
|
|
2006
|
+
.ok()?
|
|
2007
|
+
.pop()
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
fn stats(&self) -> crate::read::Stats {
|
|
2011
|
+
let num_changes = self.change_graph.len() as u64;
|
|
2012
|
+
let num_ops = self.ops.len() as u64;
|
|
2013
|
+
let num_actors = self.ops.actors.len() as u64;
|
|
2014
|
+
let cargo_package_name = env!("CARGO_PKG_NAME");
|
|
2015
|
+
let cargo_package_version = env!("CARGO_PKG_VERSION");
|
|
2016
|
+
let rustc_version = env!("CARGO_PKG_RUST_VERSION");
|
|
2017
|
+
crate::read::Stats {
|
|
2018
|
+
num_changes,
|
|
2019
|
+
num_ops,
|
|
2020
|
+
num_actors,
|
|
2021
|
+
cargo_package_name,
|
|
2022
|
+
cargo_package_version,
|
|
2023
|
+
rustc_version,
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
fn text_encoding(&self) -> TextEncoding {
|
|
2028
|
+
self.ops.text_encoding
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
impl Default for Automerge {
|
|
2033
|
+
fn default() -> Self {
|
|
2034
|
+
Self::new()
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
/// Options to pass to [`Automerge::save_with_options()`] and [`crate::AutoCommit::save_with_options()`]
|
|
2039
|
+
#[derive(Debug)]
|
|
2040
|
+
pub struct SaveOptions {
|
|
2041
|
+
/// Whether to apply DEFLATE compression to the RLE encoded columns in the document
|
|
2042
|
+
pub deflate: bool,
|
|
2043
|
+
/// Whether to save changes which we do not have the dependencies for
|
|
2044
|
+
pub retain_orphans: bool,
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
impl SaveOptions {
|
|
2048
|
+
fn compress(&self) -> CompressConfig {
|
|
2049
|
+
if self.deflate {
|
|
2050
|
+
CompressConfig::Threshold(change::DEFLATE_MIN_SIZE)
|
|
2051
|
+
} else {
|
|
2052
|
+
CompressConfig::None
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
impl std::default::Default for SaveOptions {
|
|
2058
|
+
fn default() -> Self {
|
|
2059
|
+
Self {
|
|
2060
|
+
deflate: true,
|
|
2061
|
+
retain_orphans: true,
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
#[derive(Debug)]
|
|
2067
|
+
pub(crate) struct Isolation {
|
|
2068
|
+
actor_index: usize,
|
|
2069
|
+
seq: u64,
|
|
2070
|
+
clock: Clock,
|
|
2071
|
+
}
|