yaml parser string slices

This commit is contained in:
2025-12-30 20:57:33 +09:00
parent 211b590b30
commit 8c4cb4442c

View File

@@ -10,6 +10,9 @@ use crate::{Error, Result};
/// Unity files use the YAML 1.1 multi-document format, where each document /// Unity files use the YAML 1.1 multi-document format, where each document
/// starts with `---`. This function splits the file into individual documents. /// 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 /// # Example
/// ///
/// ``` /// ```
@@ -19,48 +22,45 @@ use crate::{Error, Result};
/// let docs = split_yaml_documents(content).unwrap(); /// let docs = split_yaml_documents(content).unwrap();
/// assert_eq!(docs.len(), 2); /// assert_eq!(docs.len(), 2);
/// ``` /// ```
pub fn split_yaml_documents(content: &str) -> Result<Vec<String>> { pub fn split_yaml_documents<'a>(content: &'a str) -> Result<Vec<&'a str>> {
let mut documents = Vec::new(); let mut documents = Vec::new();
let mut current_doc = String::new(); let mut doc_start: Option<usize> = None;
let mut in_document = false; let mut pos = 0;
let mut header_lines = Vec::new();
// 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 // 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; continue;
} }
// Handle YAML headers (%YAML and %TAG) // Skip YAML headers (%YAML and %TAG)
if line.starts_with('%') { if trimmed.starts_with('%') {
if !in_document { pos += line.len();
header_lines.push(line);
}
continue; continue;
} }
// Check if this is a document separator // Check if this is a document separator
if line.starts_with("---") { if trimmed.starts_with("---") {
// If we have a current document, save it // Save previous document if exists
if !current_doc.is_empty() { if let Some(start) = doc_start {
documents.push(current_doc.trim().to_string()); documents.push(content[start..pos].trim());
current_doc.clear();
} }
// Start a new document with this line // Mark the start of the new document
current_doc.push_str(line); doc_start = Some(pos);
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');
} }
pos += line.len();
} }
// Add the last document if it exists // Add the last document if it exists
if !current_doc.is_empty() { if let Some(start) = doc_start {
documents.push(current_doc.trim().to_string()); documents.push(content[start..].trim());
} }
// Validate we found at least one document // Validate we found at least one document