rust
58 lines · 8 steps
Applying a diff hunk in Rust
A patch applier walks a hunk's lines against a buffer, verifying context before adding or removing text.
Explained by
highlit
1use std::collections::VecDeque;
2
3#[derive(Debug)]
4pub struct Hunk {
5 pub old_start: usize,
6 pub lines: Vec<HunkLine>,
7}
8
9#[derive(Debug)]
10pub enum HunkLine {
11 Context(String),
12 Removed(String),
13 Added(String),
14}
15
16#[derive(Debug)]
17pub enum PatchError {
18 ContextMismatch { line: usize, expected: String, found: String },
19 UnexpectedEof { line: usize },
20}
21
22pub fn apply_hunk(buffer: &[String], hunk: &Hunk) -> Result<Vec<String>, PatchError> {
23 let mut out: Vec<String> = buffer[..hunk.old_start.saturating_sub(1)].to_vec();
24 let mut cursor = hunk.old_start.saturating_sub(1);
25 let mut pending: VecDeque<&HunkLine> = hunk.lines.iter().collect();
26
27 while let Some(line) = pending.pop_front() {
28 match line {
29 HunkLine::Context(text) => {
30 let existing = buffer.get(cursor).ok_or(PatchError::UnexpectedEof { line: cursor + 1 })?;
31 if existing != text {
32 return Err(PatchError::ContextMismatch {
33 line: cursor + 1,
34 expected: text.clone(),
35 found: existing.clone(),
36 });
37 }
38 out.push(existing.clone());
39 cursor += 1;
40 }
41 HunkLine::Removed(text) => {
42 let existing = buffer.get(cursor).ok_or(PatchError::UnexpectedEof { line: cursor + 1 })?;
43 if existing != text {
44 return Err(PatchError::ContextMismatch {
45 line: cursor + 1,
46 expected: text.clone(),
47 found: existing.clone(),
48 });
49 }
50 cursor += 1;
51 }
52 HunkLine::Added(text) => out.push(text.clone()),
53 }
54 }
55
56 out.extend_from_slice(&buffer[cursor..]);
57 Ok(out)
58}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Modeling each diff line as an enum variant lets one match express context, removal, and addition cleanly.
- 2Verifying context and removed lines against the buffer catches stale patches before corrupting output.
- 3Returning a rich error enum lets callers report exactly which line mismatched and why.
Related explainers
go
package email import ( "errors"
Normalizing and deduping email addresses in Go
validation
normalization
deduplication
Intermediate
8 steps
rust
use std::time::Duration; use axum::{ http::{header, HeaderValue, Request},
Serving fingerprinted assets in Axum
static-assets
http-caching
middleware
Intermediate
7 steps
javascript
const express = require('express'); const multer = require('multer'); const path = require('path'); const crypto = require('crypto');
Safe image uploads with Multer in Express
file-upload
multer
validation
Intermediate
7 steps
java
@Configuration public class OrderConsumerConfig { @Bean
Wiring a resilient Kafka consumer in Spring
kafka
deserialization
error-handling
Intermediate
8 steps
rust
use axum::{ body::Body, http::{Method, StatusCode, Uri}, response::{IntoResponse, Response},
Nesting routers and JSON fallbacks in Axum
routing
http
json-responses
Intermediate
7 steps
java
@Configuration @EnableKafka public class KafkaErrorHandlingConfig {
Kafka retry and dead-letter handling in Spring
kafka
error-handling
retry
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/applying-a-diff-hunk-in-rust-explained-rust-8490/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.