use organic::types::PostBlank; use organic::types::StandardProperties; use serde::Deserialize; use serde::Serialize; use super::to_wasm::ToWasmContext; use super::to_wasm::ToWasmStandardProperties; #[derive(Debug, Serialize, Deserialize)] pub(crate) struct WasmStandardProperties { begin: usize, end: usize, contents_begin: Option, contents_end: Option, post_blank: PostBlank, } impl<'s, SP: StandardProperties<'s>> ToWasmStandardProperties for SP { type Output = WasmStandardProperties; fn to_wasm_standard_properties( &self, wasm_context: ToWasmContext<'_>, ) -> Result { let (begin, end) = get_char_indices(wasm_context.full_document, self.get_source()); let (contents_begin, contents_end) = match self.get_contents() { Some(contents) => { let (begin, end) = get_char_indices(wasm_context.full_document, contents); (Some(begin), Some(end)) } None => (None, None), }; let post_blank = self.get_post_blank(); Ok(WasmStandardProperties { begin, end, contents_begin, contents_end, post_blank, }) } } fn get_char_indices(original_document: &str, subset: &str) -> (usize, usize) { let (begin_byte, end_byte) = get_rust_byte_offsets(original_document, subset); // Add 1 to make this 1-based to match emacs. let begin_char = original_document[..begin_byte].chars().count() + 1; // Also 1-based: let end_char = begin_char + original_document[begin_byte..end_byte].chars().count(); (begin_char, end_char) } /// Get the byte offset into source that the string slice exists at. /// /// These offsets are zero-based. fn get_rust_byte_offsets(original_document: &str, subset: &str) -> (usize, usize) { debug_assert!(is_slice_of(original_document, subset)); let offset = subset.as_ptr() as usize - original_document.as_ptr() as usize; let end = offset + subset.len(); (offset, end) } /// Check if the child string slice is a slice of the parent string slice. fn is_slice_of(parent: &str, child: &str) -> bool { let parent_start = parent.as_ptr() as usize; let parent_end = parent_start + parent.len(); let child_start = child.as_ptr() as usize; let child_end = child_start + child.len(); child_start >= parent_start && child_end <= parent_end }