diff --git a/src/parser/yaml.rs b/src/parser/yaml.rs index 7edf319..88b8e6b 100644 --- a/src/parser/yaml.rs +++ b/src/parser/yaml.rs @@ -10,6 +10,9 @@ use crate::{Error, Result}; /// Unity files use the YAML 1.1 multi-document format, where each document /// starts with `---`. This function splits the file into individual documents. /// +/// Returns string slices referencing the original content, avoiding allocations. +/// Callers can convert slices to owned strings with `.to_string()` if needed. +/// /// # Example /// /// ``` @@ -19,48 +22,45 @@ use crate::{Error, Result}; /// let docs = split_yaml_documents(content).unwrap(); /// assert_eq!(docs.len(), 2); /// ``` -pub fn split_yaml_documents(content: &str) -> Result> { +pub fn split_yaml_documents<'a>(content: &'a str) -> Result> { let mut documents = Vec::new(); - let mut current_doc = String::new(); - let mut in_document = false; - let mut header_lines = Vec::new(); + let mut doc_start: Option = None; + let mut pos = 0; + + // Use split_inclusive to keep newlines, making byte position tracking easier + for line in content.split_inclusive('\n') { + // Get the line content without line endings for checking + let trimmed = line.trim_end_matches(&['\r', '\n'][..]); - for line in content.lines() { // Skip empty lines before first document - if line.trim().is_empty() && !in_document && current_doc.is_empty() { + if trimmed.is_empty() && doc_start.is_none() { + pos += line.len(); continue; } - // Handle YAML headers (%YAML and %TAG) - if line.starts_with('%') { - if !in_document { - header_lines.push(line); - } + // Skip YAML headers (%YAML and %TAG) + if trimmed.starts_with('%') { + pos += line.len(); continue; } // Check if this is a document separator - if line.starts_with("---") { - // If we have a current document, save it - if !current_doc.is_empty() { - documents.push(current_doc.trim().to_string()); - current_doc.clear(); + if trimmed.starts_with("---") { + // Save previous document if exists + if let Some(start) = doc_start { + documents.push(content[start..pos].trim()); } - // Start a new document with this line - current_doc.push_str(line); - current_doc.push('\n'); - in_document = true; - } else if in_document { - // Add line to current document - current_doc.push_str(line); - current_doc.push('\n'); + // Mark the start of the new document + doc_start = Some(pos); } + + pos += line.len(); } // Add the last document if it exists - if !current_doc.is_empty() { - documents.push(current_doc.trim().to_string()); + if let Some(start) = doc_start { + documents.push(content[start..].trim()); } // Validate we found at least one document