util.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. use crate::errors::SyncError;
  2. use dissimilar::Chunk;
  3. use document_model::document::DocumentInfo;
  4. use lib_ot::core::{DeltaOperationBuilder, OTString, OperationAttributes};
  5. use lib_ot::{
  6. core::{DeltaOperations, OperationTransform, NEW_LINE, WHITESPACE},
  7. text_delta::DeltaTextOperations,
  8. };
  9. use revision_model::Revision;
  10. use serde::de::DeserializeOwned;
  11. #[inline]
  12. pub fn find_newline(s: &str) -> Option<usize> {
  13. s.find(NEW_LINE)
  14. }
  15. #[inline]
  16. pub fn is_newline(s: &str) -> bool {
  17. s == NEW_LINE
  18. }
  19. #[inline]
  20. pub fn is_whitespace(s: &str) -> bool {
  21. s == WHITESPACE
  22. }
  23. #[inline]
  24. pub fn contain_newline(s: &str) -> bool {
  25. s.contains(NEW_LINE)
  26. }
  27. pub fn recover_operation_from_revisions<T>(
  28. revisions: Vec<Revision>,
  29. validator: impl Fn(&DeltaOperations<T>) -> bool,
  30. ) -> Option<(DeltaOperations<T>, i64)>
  31. where
  32. T: OperationAttributes + DeserializeOwned + OperationAttributes,
  33. {
  34. let mut new_operations = DeltaOperations::<T>::new();
  35. let mut rev_id = 0;
  36. for revision in revisions {
  37. if let Ok(operations) = DeltaOperations::<T>::from_bytes(revision.bytes) {
  38. match new_operations.compose(&operations) {
  39. Ok(composed_operations) => {
  40. if validator(&composed_operations) {
  41. rev_id = revision.rev_id;
  42. new_operations = composed_operations;
  43. } else {
  44. break;
  45. }
  46. },
  47. Err(_) => break,
  48. }
  49. } else {
  50. break;
  51. }
  52. }
  53. if new_operations.is_empty() {
  54. None
  55. } else {
  56. Some((new_operations, rev_id))
  57. }
  58. }
  59. #[inline]
  60. pub fn make_document_info_from_revisions(
  61. doc_id: &str,
  62. revisions: Vec<Revision>,
  63. ) -> Result<Option<DocumentInfo>, SyncError> {
  64. if revisions.is_empty() {
  65. return Ok(None);
  66. }
  67. let mut delta = DeltaTextOperations::new();
  68. let mut base_rev_id = 0;
  69. let mut rev_id = 0;
  70. for revision in revisions {
  71. base_rev_id = revision.base_rev_id;
  72. rev_id = revision.rev_id;
  73. if revision.bytes.is_empty() {
  74. tracing::warn!("revision delta_data is empty");
  75. }
  76. let new_delta = DeltaTextOperations::from_bytes(revision.bytes)?;
  77. delta = delta.compose(&new_delta)?;
  78. }
  79. Ok(Some(DocumentInfo {
  80. doc_id: doc_id.to_owned(),
  81. data: delta.json_bytes().to_vec(),
  82. rev_id,
  83. base_rev_id,
  84. }))
  85. }
  86. #[inline]
  87. pub fn rev_id_from_str(s: &str) -> Result<i64, SyncError> {
  88. let rev_id = s
  89. .to_owned()
  90. .parse::<i64>()
  91. .map_err(|e| SyncError::internal().context(format!("Parse rev_id from {} failed. {}", s, e)))?;
  92. Ok(rev_id)
  93. }
  94. pub fn cal_diff<T: OperationAttributes>(old: String, new: String) -> Option<DeltaOperations<T>> {
  95. let chunks = dissimilar::diff(&old, &new);
  96. let mut delta_builder = DeltaOperationBuilder::<T>::new();
  97. for chunk in &chunks {
  98. match chunk {
  99. Chunk::Equal(s) => {
  100. delta_builder = delta_builder.retain(OTString::from(*s).utf16_len());
  101. },
  102. Chunk::Delete(s) => {
  103. delta_builder = delta_builder.delete(OTString::from(*s).utf16_len());
  104. },
  105. Chunk::Insert(s) => {
  106. delta_builder = delta_builder.insert(s);
  107. },
  108. }
  109. }
  110. let delta = delta_builder.build();
  111. if delta.is_empty() {
  112. None
  113. } else {
  114. Some(delta)
  115. }
  116. }