#[derive(Debug, Clone)]
pub struct WorkerTask {
pub id: String,
pub target: String,
pub instruction: String,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Hunk {
pub start_line: usize,
pub end_line: usize,
pub content: String,
pub worker_id: String,
}
impl Hunk {
#[allow(dead_code)]
pub fn sort_key(&self) -> (std::cmp::Reverse<usize>, std::cmp::Reverse<usize>) {
(
std::cmp::Reverse(self.start_line),
std::cmp::Reverse(self.end_line),
)
}
}
pub fn parse_master_spec(xml_content: &str) -> Vec<WorkerTask> {
let mut tasks = Vec::new();
let iter = xml_content.split("<worker_task");
for block in iter.skip(1) {
let Some(tag_end) = block.find('>') else {
continue;
};
let tag_attrs = &block[..tag_end];
let Some(id_attr_pos) = tag_attrs.find("id=\"") else {
continue;
};
let id_start = id_attr_pos + 4;
let Some(id_end_rel) = tag_attrs[id_start..].find('"') else {
continue;
};
let id = &tag_attrs[id_start..id_start + id_end_rel];
let Some(target_attr_pos) = tag_attrs.find("target=\"") else {
continue;
};
let target_start = target_attr_pos + 8;
let Some(target_end_rel) = tag_attrs[target_start..].find('"') else {
continue;
};
let target = &tag_attrs[target_start..target_start + target_end_rel];
let content_block = &block[tag_end + 1..];
let Some(content_end) = content_block.find("</worker_task>") else {
continue;
};
let instruction = content_block[..content_end].trim();
tasks.push(WorkerTask {
id: id.to_string(),
target: target.to_string(),
instruction: instruction.to_string(),
});
}
tasks
}
#[allow(dead_code)]
pub fn parse_scratchpad_diffs(raw_content: &str, worker_id: String) -> Vec<Hunk> {
let mut hunks = Vec::new();
let mut current_pos = 0;
fn parse_attr(attr_str: &str, key: &str) -> Option<usize> {
let klen = key.len();
let bytes = attr_str.as_bytes();
let mut pos = 0;
while let Some(rel) = attr_str[pos..].find(key) {
let abs = pos + rel;
let after = abs + klen;
if bytes.get(after).copied() == Some(b'=')
&& bytes.get(after + 1).copied() == Some(b'"')
{
let val_start = after + 2;
let end = attr_str[val_start..].find('"')? + val_start;
return attr_str[val_start..end].parse().ok();
}
pos = abs + 1;
}
None
}
while let Some(start_idx) = raw_content[current_pos..].find("<patch") {
let absolute_start = current_pos + start_idx;
let Some(tag_end) = raw_content[absolute_start..].find('>') else {
break;
};
let attr_str = &raw_content[absolute_start..absolute_start + tag_end];
let start_line = parse_attr(attr_str, "start").unwrap_or(0);
let end_line = parse_attr(attr_str, "end").unwrap_or(0);
let body_start = absolute_start + tag_end + 1;
if let Some(end_idx) = raw_content[body_start..].find("</patch>") {
let content = raw_content[body_start..body_start + end_idx]
.trim()
.to_string();
hunks.push(Hunk {
start_line,
end_line,
content,
worker_id: worker_id.clone(),
});
current_pos = body_start + end_idx + 8;
} else {
break;
}
}
hunks
}