diff --git a/src/compare/util.rs b/src/compare/util.rs index d12ee6d..1804cd9 100644 --- a/src/compare/util.rs +++ b/src/compare/util.rs @@ -1,5 +1,5 @@ use super::sexp::Token; -use crate::types::Source; +use crate::types::StandardProperties; /// Check if the child string slice is a slice of the parent string slice. fn is_slice_of(parent: &str, child: &str) -> bool { @@ -10,13 +10,16 @@ fn is_slice_of(parent: &str, child: &str) -> bool { child_start >= parent_start && child_end <= parent_end } -/// Get the offset into source that the rust object exists at. +/// Get the byte offset into source that the rust object exists at. /// /// These offsets are zero-based unlike the elisp ones. -fn get_offsets<'s, S: Source<'s>>(source: &'s str, rust_object: &'s S) -> (usize, usize) { - let rust_object_source = rust_object.get_source(); - assert!(is_slice_of(source, rust_object_source)); - let offset = rust_object_source.as_ptr() as usize - source.as_ptr() as usize; +fn get_rust_byte_offsets<'s, S: StandardProperties<'s>>( + original_document: &'s str, + rust_ast_node: &'s S, +) -> (usize, usize) { + let rust_object_source = rust_ast_node.get_source(); + debug_assert!(is_slice_of(original_document, rust_object_source)); + let offset = rust_object_source.as_ptr() as usize - original_document.as_ptr() as usize; let end = offset + rust_object_source.len(); (offset, end) } @@ -40,24 +43,27 @@ pub(crate) fn assert_name<'s>( Ok(()) } -pub(crate) fn assert_bounds<'s, S: Source<'s>>( - source: &'s str, +/// Assert that the character ranges defined by upstream org-mode's :standard-properties match the slices in Organic's StandardProperties. +/// +/// This does **not** handle plain text because plain text is a special case. +pub(crate) fn assert_bounds<'s, S: StandardProperties<'s>>( + original_document: &'s str, emacs: &'s Token<'s>, rust: &'s S, ) -> Result<(), Box> { - let standard_properties = get_emacs_standard_properties(emacs)?; + let standard_properties = get_emacs_standard_properties(emacs)?; // 1-based let (begin, end) = ( standard_properties .begin .ok_or("Token should have a begin.")?, standard_properties.end.ok_or("Token should have an end.")?, ); - let (rust_begin, rust_end) = get_offsets(source, rust); - let rust_begin_char_offset = (&source[..rust_begin]).chars().count(); + let (rust_begin, rust_end) = get_rust_byte_offsets(original_document, rust); // 0-based + let rust_begin_char_offset = (&original_document[..rust_begin]).chars().count() + 1; // 1-based let rust_end_char_offset = - rust_begin_char_offset + (&source[rust_begin..rust_end]).chars().count(); - if (rust_begin_char_offset + 1) != begin || (rust_end_char_offset + 1) != end { - Err(format!("Rust bounds (in chars) ({rust_begin}, {rust_end}) do not match emacs bounds ({emacs_begin}, {emacs_end})", rust_begin = rust_begin_char_offset + 1, rust_end = rust_end_char_offset + 1, emacs_begin=begin, emacs_end=end))?; + rust_begin_char_offset + (&original_document[rust_begin..rust_end]).chars().count(); // 1-based + if rust_begin_char_offset != begin || rust_end_char_offset != end { + Err(format!("Rust bounds (in chars) ({rust_begin}, {rust_end}) do not match emacs bounds ({emacs_begin}, {emacs_end})", rust_begin = rust_begin_char_offset, rust_end = rust_end_char_offset, emacs_begin=begin, emacs_end=end))?; } Ok(())