lib.rs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //! Core logic for Rustpad, shared with the client through WebAssembly.
  2. #![warn(missing_docs)]
  3. use operational_transform::OperationSeq;
  4. use serde::{Deserialize, Serialize};
  5. use wasm_bindgen::prelude::*;
  6. pub mod utils;
  7. /// This is an wrapper around `operational_transform::OperationSeq`, which is
  8. /// necessary for Wasm compatibility through `wasm-bindgen`.
  9. #[wasm_bindgen]
  10. #[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
  11. pub struct OpSeq(OperationSeq);
  12. /// This is a pair of `OpSeq` structs, which is needed to handle some return
  13. /// values from `wasm-bindgen`.
  14. #[wasm_bindgen]
  15. #[derive(Default, Clone, Debug, PartialEq)]
  16. pub struct OpSeqPair(OpSeq, OpSeq);
  17. impl OpSeq {
  18. /// Transforms two operations A and B that happened concurrently and produces
  19. /// two operations A' and B' (in an array) such that
  20. /// `apply(apply(S, A), B') = apply(apply(S, B), A')`.
  21. /// This function is the heart of OT.
  22. ///
  23. /// Unlike `OpSeq::transform`, this function returns a raw tuple, which is
  24. /// more efficient but cannot be exported by `wasm-bindgen`.
  25. ///
  26. /// # Error
  27. ///
  28. /// Returns `None` if the operations cannot be transformed due to
  29. /// length conflicts.
  30. pub fn transform_raw(&self, other: &OpSeq) -> Option<(OpSeq, OpSeq)> {
  31. let (a, b) = self.0.transform(&other.0).ok()?;
  32. Some((Self(a), Self(b)))
  33. }
  34. }
  35. #[wasm_bindgen]
  36. impl OpSeq {
  37. /// Creates a default empty `OpSeq`.
  38. pub fn new() -> Self {
  39. Self::default()
  40. }
  41. /// Creates a store for operatations which does not need to allocate until
  42. /// `capacity` operations have been stored inside.
  43. pub fn with_capacity(capacity: usize) -> Self {
  44. Self(OperationSeq::with_capacity(capacity))
  45. }
  46. /// Merges the operation with `other` into one operation while preserving
  47. /// the changes of both. Or, in other words, for each input string S and a
  48. /// pair of consecutive operations A and B.
  49. /// `apply(apply(S, A), B) = apply(S, compose(A, B))`
  50. /// must hold.
  51. ///
  52. /// # Error
  53. ///
  54. /// Returns `None` if the operations are not composable due to length
  55. /// conflicts.
  56. pub fn compose(&self, other: &OpSeq) -> Option<OpSeq> {
  57. self.0.compose(&other.0).ok().map(Self)
  58. }
  59. /// Deletes `n` characters at the current cursor position.
  60. pub fn delete(&mut self, n: u32) {
  61. self.0.delete(n as u64)
  62. }
  63. /// Inserts a `s` at the current cursor position.
  64. pub fn insert(&mut self, s: &str) {
  65. self.0.insert(s)
  66. }
  67. /// Moves the cursor `n` characters forwards.
  68. pub fn retain(&mut self, n: u32) {
  69. self.0.retain(n as u64)
  70. }
  71. /// Transforms two operations A and B that happened concurrently and produces
  72. /// two operations A' and B' (in an array) such that
  73. /// `apply(apply(S, A), B') = apply(apply(S, B), A')`.
  74. /// This function is the heart of OT.
  75. ///
  76. /// # Error
  77. ///
  78. /// Returns `None` if the operations cannot be transformed due to
  79. /// length conflicts.
  80. pub fn transform(&self, other: &OpSeq) -> Option<OpSeqPair> {
  81. let (a, b) = self.0.transform(&other.0).ok()?;
  82. Some(OpSeqPair(Self(a), Self(b)))
  83. }
  84. /// Applies an operation to a string, returning a new string.
  85. ///
  86. /// # Error
  87. ///
  88. /// Returns an error if the operation cannot be applied due to length
  89. /// conflicts.
  90. pub fn apply(&self, s: &str) -> Option<String> {
  91. self.0.apply(s).ok()
  92. }
  93. /// Computes the inverse of an operation. The inverse of an operation is the
  94. /// operation that reverts the effects of the operation, e.g. when you have
  95. /// an operation 'insert("hello "); skip(6);' then the inverse is
  96. /// 'delete("hello "); skip(6);'. The inverse should be used for
  97. /// implementing undo.
  98. pub fn invert(&self, s: &str) -> Self {
  99. Self(self.0.invert(s))
  100. }
  101. /// Checks if this operation has no effect.
  102. #[inline]
  103. pub fn is_noop(&self) -> bool {
  104. self.0.is_noop()
  105. }
  106. /// Returns the length of a string these operations can be applied to
  107. #[inline]
  108. pub fn base_len(&self) -> usize {
  109. self.0.base_len()
  110. }
  111. /// Returns the length of the resulting string after the operations have
  112. /// been applied.
  113. #[inline]
  114. pub fn target_len(&self) -> usize {
  115. self.0.target_len()
  116. }
  117. /// Return the new index of a position in the string.
  118. pub fn transform_index(&self, position: u32) -> u32 {
  119. let mut index = position as i32;
  120. let mut new_index = index;
  121. for op in self.0.ops() {
  122. use operational_transform::Operation::*;
  123. match op {
  124. &Retain(n) => index -= n as i32,
  125. Insert(s) => new_index += bytecount::num_chars(s.as_bytes()) as i32,
  126. &Delete(n) => {
  127. new_index -= std::cmp::min(index, n as i32);
  128. index -= n as i32;
  129. }
  130. }
  131. if index < 0 {
  132. break;
  133. }
  134. }
  135. new_index as u32
  136. }
  137. /// Attempts to deserialize an `OpSeq` from a JSON string.
  138. #[allow(clippy::should_implement_trait)]
  139. pub fn from_str(s: &str) -> Option<OpSeq> {
  140. serde_json::from_str(s).ok()
  141. }
  142. /// Converts this object to a JSON string.
  143. #[allow(clippy::inherent_to_string)]
  144. pub fn to_string(&self) -> String {
  145. serde_json::to_string(self).expect("json serialization failure")
  146. }
  147. }
  148. #[wasm_bindgen]
  149. impl OpSeqPair {
  150. /// Returns the first element of the pair.
  151. pub fn first(&self) -> OpSeq {
  152. self.0.clone()
  153. }
  154. /// Returns the second element of the pair.
  155. pub fn second(&self) -> OpSeq {
  156. self.1.clone()
  157. }
  158. }