2023-04-21 20:32:51 -04:00
use crate ::parser ::sexp ::Token ;
2023-04-11 19:16:04 -04:00
use crate ::parser ::Source ;
/// 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
}
/// Get the offset into source that the rust object exists at.
///
/// These offsets are zero-based unlike the elisp ones.
pub 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 ;
let end = offset + rust_object_source . len ( ) ;
( offset , end )
}
2023-04-19 15:19:21 -04:00
pub fn assert_name < ' s > ( emacs : & ' s Token < ' s > , name : & str ) -> Result < ( ) , Box < dyn std ::error ::Error > > {
let children = emacs . as_list ( ) ? ;
let first_child = children
. first ( )
. ok_or ( " Should have at least one child. " ) ?
. as_atom ( ) ? ;
if first_child ! = name {
Err ( format! (
" Expected a {expected} cell, but found a {found} cell. " ,
expected = name ,
found = first_child
) ) ? ;
}
Ok ( ( ) )
}
2023-04-19 15:29:46 -04:00
pub fn assert_bounds < ' s , S : Source < ' s > > (
source : & ' s str ,
emacs : & ' s Token < ' s > ,
rust : & ' s S ,
) -> Result < ( ) , Box < dyn std ::error ::Error > > {
let children = emacs . as_list ( ) ? ;
let attributes_child = children
. iter ( )
. nth ( 1 )
. ok_or ( " Should have an attributes child. " ) ? ;
let attributes_map = attributes_child . as_map ( ) ? ;
let begin = attributes_map
. get ( " :begin " )
. ok_or ( " Missing :begin attribute. " ) ?
. as_atom ( ) ? ;
let end = attributes_map
. get ( " :end " )
. ok_or ( " Missing :end attribute. " ) ?
. as_atom ( ) ? ;
let ( rust_begin , rust_end ) = get_offsets ( source , rust ) ;
if ( rust_begin + 1 ) . to_string ( ) ! = begin | | ( rust_end + 1 ) . to_string ( ) ! = end {
Err ( format! ( " Rust bounds ( {rust_begin} , {rust_end} ) do not match emacs bounds ( {emacs_begin} , {emacs_end} ) " , rust_begin = rust_begin + 1 , rust_end = rust_end + 1 , emacs_begin = begin , emacs_end = end ) ) ? ;
}
Ok ( ( ) )
}