Merge crates
This commit is contained in:
parent
82e77eec89
commit
bcbac03228
60 changed files with 73 additions and 248 deletions
42
Cargo.lock
generated
42
Cargo.lock
generated
|
|
@ -2,12 +2,6 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
|
|
@ -206,11 +200,14 @@ dependencies = [
|
|||
name = "reconcile"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"insta",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"test-case",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -290,19 +287,6 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_lib"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"console_error_panic_hook",
|
||||
"insta",
|
||||
"reconcile",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case"
|
||||
version = "3.3.1"
|
||||
|
|
@ -336,26 +320,6 @@ dependencies = [
|
|||
"test-case-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
|
|
|
|||
43
Cargo.toml
43
Cargo.toml
|
|
@ -1,21 +1,38 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"reconcile",
|
||||
"sync_lib"
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
rust-version = "1.83"
|
||||
[package]
|
||||
name = "reconcile"
|
||||
rust-version = "1.85"
|
||||
authors = ["Andras Schmelczer <andras@schmelczer.dev>"]
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/schmelczer/vault-link"
|
||||
repository = "https://github.com/schmelczer/reconcile"
|
||||
version = "0.4.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
serde = { version = "1.0.219", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "2.0.12", default-features = false }
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.219", optional = true, features = ["derive"] }
|
||||
|
||||
wasm-bindgen = { version = "0.2.99", optional = true }
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
# logging them with `console.error`. This is great for development, but requires
|
||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||
# code size when deploying.
|
||||
console_error_panic_hook = { version = "0.1.7", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["serde", "wasm"]
|
||||
serde = [ "dep:serde" ]
|
||||
wasm = [ "dep:wasm-bindgen", "dep:console_error_panic_hook" ]
|
||||
|
||||
[dev-dependencies]
|
||||
insta = "1.42.2"
|
||||
pretty_assertions = "1.4.1"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_yaml ="0.9.34"
|
||||
test-case = "3.3.1"
|
||||
wasm-bindgen-test = "0.3.49"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
[package]
|
||||
name = "reconcile"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.219", optional = true, features = ["derive"] }
|
||||
|
||||
[features]
|
||||
serde = [ "dep:serde" ]
|
||||
|
||||
[dev-dependencies]
|
||||
insta = "1.42.2"
|
||||
pretty_assertions = "1.4.1"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_yaml ="0.9.34"
|
||||
test-case = "3.3.1"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
@ -8,3 +8,6 @@ pub use operation_transformation::{
|
|||
reconcile_with_tokenizer,
|
||||
};
|
||||
pub use tokenizer::{Tokenizer, token::Token, word_tokenizer::word_tokenizer};
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
pub mod wasm;
|
||||
2
src/wasm.rs
Normal file
2
src/wasm.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
pub mod cursor;
|
||||
pub mod lib;
|
||||
|
|
@ -3,27 +3,27 @@ use wasm_bindgen::prelude::*;
|
|||
/// Wrapper type to expose `TextWithCursors` to JS.
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct TextWithCursors {
|
||||
pub struct JsTextWithCursors {
|
||||
text: String,
|
||||
cursors: Vec<CursorPosition>,
|
||||
cursors: Vec<JsCursorPosition>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl TextWithCursors {
|
||||
impl JsTextWithCursors {
|
||||
#[wasm_bindgen(constructor)]
|
||||
#[must_use]
|
||||
pub fn new(text: String, cursors: Vec<CursorPosition>) -> Self { Self { text, cursors } }
|
||||
pub fn new(text: String, cursors: Vec<JsCursorPosition>) -> Self { Self { text, cursors } }
|
||||
|
||||
#[must_use]
|
||||
pub fn text(&self) -> String { self.text.clone() }
|
||||
|
||||
#[must_use]
|
||||
pub fn cursors(&self) -> Vec<CursorPosition> { self.cursors.clone() }
|
||||
pub fn cursors(&self) -> Vec<JsCursorPosition> { self.cursors.clone() }
|
||||
}
|
||||
|
||||
impl From<TextWithCursors> for reconcile::TextWithCursors<'_> {
|
||||
fn from(owned: TextWithCursors) -> Self {
|
||||
reconcile::TextWithCursors::new_owned(
|
||||
impl From<JsTextWithCursors> for crate::TextWithCursors<'_> {
|
||||
fn from(owned: JsTextWithCursors) -> Self {
|
||||
crate::TextWithCursors::new_owned(
|
||||
owned.text.to_string(),
|
||||
owned
|
||||
.cursors
|
||||
|
|
@ -34,9 +34,9 @@ impl From<TextWithCursors> for reconcile::TextWithCursors<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<reconcile::TextWithCursors<'_>> for TextWithCursors {
|
||||
fn from(text_with_cursors: reconcile::TextWithCursors<'_>) -> Self {
|
||||
TextWithCursors {
|
||||
impl From<crate::TextWithCursors<'_>> for JsTextWithCursors {
|
||||
fn from(text_with_cursors: crate::TextWithCursors<'_>) -> Self {
|
||||
JsTextWithCursors {
|
||||
text: text_with_cursors.text.into_owned(),
|
||||
cursors: text_with_cursors
|
||||
.cursors
|
||||
|
|
@ -50,13 +50,13 @@ impl From<reconcile::TextWithCursors<'_>> for TextWithCursors {
|
|||
/// Wrapper type to expose `CursorPosition` to JS.
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct CursorPosition {
|
||||
pub struct JsCursorPosition {
|
||||
id: usize,
|
||||
char_index: usize,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl CursorPosition {
|
||||
impl JsCursorPosition {
|
||||
#[wasm_bindgen(constructor)]
|
||||
#[must_use]
|
||||
pub fn new(id: usize, char_index: usize) -> Self { Self { id, char_index } }
|
||||
|
|
@ -69,18 +69,18 @@ impl CursorPosition {
|
|||
pub fn char_index(&self) -> usize { self.char_index }
|
||||
}
|
||||
|
||||
impl From<CursorPosition> for reconcile::CursorPosition {
|
||||
fn from(owned: CursorPosition) -> Self {
|
||||
reconcile::CursorPosition {
|
||||
impl From<JsCursorPosition> for crate::CursorPosition {
|
||||
fn from(owned: JsCursorPosition) -> Self {
|
||||
crate::CursorPosition {
|
||||
id: owned.id,
|
||||
char_index: owned.char_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<reconcile::CursorPosition> for CursorPosition {
|
||||
fn from(cursor: reconcile::CursorPosition) -> Self {
|
||||
CursorPosition {
|
||||
impl From<crate::CursorPosition> for JsCursorPosition {
|
||||
fn from(cursor: crate::CursorPosition) -> Self {
|
||||
JsCursorPosition {
|
||||
id: cursor.id,
|
||||
char_index: cursor.char_index,
|
||||
}
|
||||
|
|
@ -11,56 +11,9 @@
|
|||
|
||||
use core::str;
|
||||
|
||||
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
||||
use cursor::TextWithCursors;
|
||||
use errors::SyncLibError;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub mod cursor;
|
||||
pub mod errors;
|
||||
|
||||
/// Encode binary data for easy transport over HTTP. Inverse of
|
||||
/// `base64_to_bytes`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `input`: The binary data to encode.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// The base64-encoded string.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the input is not valid UTF-8.
|
||||
#[wasm_bindgen(js_name = bytesToBase64)]
|
||||
#[must_use]
|
||||
pub fn bytes_to_base64(input: &[u8]) -> String {
|
||||
set_panic_hook();
|
||||
|
||||
STANDARD.encode(input)
|
||||
}
|
||||
|
||||
/// Inverse of `bytes_to_base64`.
|
||||
/// Decode base64-encoded data into binary data.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `input`: The base64-encoded string.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// The decoded binary data.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the input is not valid base64.
|
||||
#[wasm_bindgen(js_name = base64ToBytes)]
|
||||
pub fn base64_to_bytes(input: &str) -> Result<Vec<u8>, SyncLibError> {
|
||||
set_panic_hook();
|
||||
|
||||
STANDARD.decode(input).map_err(SyncLibError::from)
|
||||
}
|
||||
use crate::wasm::cursor::JsTextWithCursors;
|
||||
|
||||
/// Merge two documents with a common parent. Relies on `reconcile::reconcile`
|
||||
/// for texts and returns the right document as-is if either of the updated
|
||||
|
|
@ -87,7 +40,7 @@ pub fn merge(parent: &[u8], left: &[u8], right: &[u8]) -> Vec<u8> {
|
|||
if is_binary(parent) || is_binary(left) || is_binary(right) {
|
||||
right.to_vec()
|
||||
} else {
|
||||
reconcile::reconcile(
|
||||
crate::reconcile(
|
||||
str::from_utf8(parent).expect("parent must be valid UTF-8 because it's not binary"),
|
||||
str::from_utf8(left).expect("left must be valid UTF-8 because it's not binary"),
|
||||
str::from_utf8(right).expect("right must be valid UTF-8 because it's not binary"),
|
||||
|
|
@ -96,13 +49,13 @@ pub fn merge(parent: &[u8], left: &[u8], right: &[u8]) -> Vec<u8> {
|
|||
}
|
||||
}
|
||||
|
||||
/// WASM wrapper around `reconcile::reconcile` for merging text.
|
||||
/// WASM wrapper around `crate::reconcile` for merging text.
|
||||
#[wasm_bindgen(js_name = mergeText)]
|
||||
#[must_use]
|
||||
pub fn merge_text(parent: &str, left: &str, right: &str) -> String {
|
||||
set_panic_hook();
|
||||
|
||||
reconcile::reconcile(parent, left, right)
|
||||
crate::reconcile(parent, left, right)
|
||||
}
|
||||
|
||||
/// WASM wrapper around `reconcile::reconcile_with_cursors` for merging text.
|
||||
|
|
@ -110,12 +63,12 @@ pub fn merge_text(parent: &str, left: &str, right: &str) -> String {
|
|||
#[must_use]
|
||||
pub fn merge_text_with_cursors(
|
||||
parent: &str,
|
||||
left: TextWithCursors,
|
||||
right: TextWithCursors,
|
||||
) -> TextWithCursors {
|
||||
left: JsTextWithCursors,
|
||||
right: JsTextWithCursors,
|
||||
) -> JsTextWithCursors {
|
||||
set_panic_hook();
|
||||
|
||||
reconcile::reconcile_with_cursors(parent, left.into(), right.into()).into()
|
||||
crate::reconcile_with_cursors(parent, left.into(), right.into()).into()
|
||||
}
|
||||
|
||||
/// Heuristically determine if the given data is a binary or a text file's
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
[package]
|
||||
name = "sync_lib"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.22.1"
|
||||
reconcile = { path = "../reconcile" }
|
||||
wasm-bindgen = "0.2.99"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
# logging them with `console.error`. This is great for development, but requires
|
||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||
# code size when deploying.
|
||||
console_error_panic_hook = { version = "0.1.7", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.49"
|
||||
insta = "1.42.2"
|
||||
|
||||
[features]
|
||||
default = ["console_error_panic_hook"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
use base64::DecodeError;
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum SyncLibError {
|
||||
#[error("Base64 decoding error because of {}", .reason)]
|
||||
Base64DecodingError { reason: String },
|
||||
}
|
||||
|
||||
impl From<DecodeError> for SyncLibError {
|
||||
fn from(e: DecodeError) -> Self {
|
||||
SyncLibError::Base64DecodingError {
|
||||
reason: e.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::string::FromUtf8Error> for SyncLibError {
|
||||
fn from(e: std::string::FromUtf8Error) -> Self {
|
||||
SyncLibError::Base64DecodingError {
|
||||
reason: e.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SyncLibError> for JsValue {
|
||||
fn from(val: SyncLibError) -> Self { JsValue::from_str(&val.to_string()) }
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
source: sync_lib/tests/web.rs
|
||||
expression: base64_to_bytes(input)
|
||||
snapshot_kind: text
|
||||
---
|
||||
Err(
|
||||
Base64DecodingError {
|
||||
reason: "Invalid symbol 61, offset 0.",
|
||||
},
|
||||
)
|
||||
|
|
@ -1,30 +1,10 @@
|
|||
use insta::assert_debug_snapshot;
|
||||
use sync_lib::{
|
||||
cursor::{CursorPosition, TextWithCursors},
|
||||
*,
|
||||
use reconcile::wasm::{
|
||||
cursor::{JsCursorPosition, JsTextWithCursors},
|
||||
lib::{is_binary, is_file_type_mergable, merge, merge_text, merge_text_with_cursors},
|
||||
};
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
#[wasm_bindgen_test(unsupported = test)]
|
||||
fn test_bytes_to_base64() {
|
||||
let input = b"hello";
|
||||
let expected = "aGVsbG8=";
|
||||
assert_eq!(bytes_to_base64(input), expected);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test(unsupported = test)]
|
||||
fn test_base64_to_bytes() {
|
||||
let input = "aGVsbG8=";
|
||||
let expected = b"hello".to_vec();
|
||||
assert_eq!(base64_to_bytes(input).unwrap(), expected);
|
||||
}
|
||||
|
||||
#[test] // insta doesn't support wasm-bindgen-test
|
||||
fn test_base64_to_bytes_error() {
|
||||
let input = "===";
|
||||
assert_debug_snapshot!(base64_to_bytes(input));
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test(unsupported = test)]
|
||||
fn test_merge() {
|
||||
let left = b"hello ";
|
||||
|
|
@ -50,18 +30,18 @@ fn test_merge_text() {
|
|||
fn test_merge_text_with_cursors() {
|
||||
let result = merge_text_with_cursors(
|
||||
"hi",
|
||||
TextWithCursors::new("hi world".to_owned(), vec![]),
|
||||
TextWithCursors::new(
|
||||
JsTextWithCursors::new("hi world".to_owned(), vec![]),
|
||||
JsTextWithCursors::new(
|
||||
"hi".to_owned(),
|
||||
vec![CursorPosition::new(0, 1), CursorPosition::new(1, 2)],
|
||||
vec![JsCursorPosition::new(0, 1), JsCursorPosition::new(1, 2)],
|
||||
),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
TextWithCursors::new(
|
||||
JsTextWithCursors::new(
|
||||
"hi world".to_owned(),
|
||||
vec![CursorPosition::new(0, 1), CursorPosition::new(1, 2)]
|
||||
vec![JsCursorPosition::new(0, 1), JsCursorPosition::new(1, 2)]
|
||||
),
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue