java_diff_utils_rs/patch/
chunk.rs1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4use super::error::PatchError;
5use super::verify_chunk::VerifyChunk;
6
7#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
9#[serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))]
10pub struct Chunk<T> {
11 position: usize,
12 lines: Vec<T>,
13 change_position: Option<Vec<usize>>,
14}
15
16impl<T> Chunk<T> {
17 pub fn new(position: usize, lines: Vec<T>, change_position: Option<Vec<usize>>) -> Self {
19 Self {
20 position,
21 lines,
22 change_position,
23 }
24 }
25
26 pub fn with_lines(position: usize, lines: Vec<T>) -> Self {
28 Self::new(position, lines, None)
29 }
30
31 pub fn verify_chunk(&self, target: &[T]) -> Result<VerifyChunk, PatchError>
33 where
34 T: PartialEq,
35 {
36 self.verify_chunk_at(target, 0, self.position)
37 }
38
39 pub fn verify_chunk_at(
41 &self,
42 target: &[T],
43 fuzz: usize,
44 position: usize,
45 ) -> Result<VerifyChunk, PatchError>
46 where
47 T: PartialEq,
48 {
49 let start_index = fuzz;
50 let last_index = self.len().saturating_sub(fuzz);
51 let last = position + self.len().saturating_sub(1);
52
53 if position.saturating_add(fuzz) > target.len() || last.saturating_sub(fuzz) > target.len()
54 {
55 return Ok(VerifyChunk::PositionOutOfTarget);
56 }
57
58 for i in start_index..last_index {
59 let target_idx = position + i;
60 if target_idx >= target.len() || target[target_idx] != self.lines[i] {
61 return Ok(VerifyChunk::ContentDoesNotMatchTarget);
62 }
63 }
64
65 Ok(VerifyChunk::Ok)
66 }
67 #[inline]
69 pub fn position(&self) -> usize {
70 self.position
71 }
72
73 #[inline]
75 pub fn lines(&self) -> &[T] {
76 &self.lines
77 }
78
79 #[inline]
81 pub fn lines_mut(&mut self) -> &mut Vec<T> {
82 &mut self.lines
83 }
84
85 pub fn set_lines(&mut self, lines: Vec<T>) {
87 self.lines = lines;
88 }
89
90 #[inline]
92 pub fn change_position(&self) -> Option<&[usize]> {
93 self.change_position.as_deref()
94 }
95
96 #[inline]
98 pub fn len(&self) -> usize {
99 self.lines.len()
100 }
101
102 #[inline]
104 pub fn size(&self) -> usize {
105 self.lines.len()
106 }
107
108 #[inline]
110 pub fn is_empty(&self) -> bool {
111 self.lines.is_empty()
112 }
113
114 #[inline]
116 pub fn last(&self) -> usize {
117 if self.lines.is_empty() {
118 self.position
119 } else {
120 self.position + self.lines.len() - 1
121 }
122 }
123}
124
125impl<T: fmt::Debug> fmt::Display for Chunk<T> {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 write!(
128 f,
129 "[position: {}, size: {}, lines: {:?}]",
130 self.position,
131 self.len(),
132 self.lines
133 )
134 }
135}