2023-10-06 14:07:25 -04:00
use std ::fmt ::Debug ;
2023-10-06 13:40:11 -04:00
use super ::diff ::DiffStatus ;
2023-10-08 14:40:01 -04:00
use super ::sexp ::unquote ;
2023-10-06 13:40:11 -04:00
use super ::sexp ::Token ;
2023-10-06 18:30:08 -04:00
use super ::util ::get_property ;
2023-10-06 13:40:11 -04:00
use super ::util ::get_property_quoted_string ;
2023-10-06 18:30:08 -04:00
use super ::util ::get_property_unquoted_atom ;
2023-10-06 13:40:11 -04:00
#[ derive(Debug) ]
pub ( crate ) enum EmacsField < ' s > {
Required ( & ' s str ) ,
2023-10-06 14:07:25 -04:00
#[ allow(dead_code) ]
2023-10-06 13:40:11 -04:00
Optional ( & ' s str ) ,
}
2023-10-06 14:07:25 -04:00
/// Do no comparison.
///
/// This is for when you want to acknowledge that a field exists in the emacs token, but you do not have any validation for it when using the compare_properties!() macro. Ideally, this should be kept to a minimum since this represents untested values.
#[ allow(dead_code) ]
2023-10-06 16:32:49 -04:00
pub ( crate ) fn compare_noop < ' b , ' s , ' x , R , RG > (
2023-10-06 14:07:25 -04:00
_emacs : & ' b Token < ' s > ,
2023-10-06 16:19:43 -04:00
_rust_node : R ,
2023-10-06 14:07:25 -04:00
_emacs_field : & ' x str ,
2023-10-06 16:19:43 -04:00
_rust_value_getter : RG ,
2023-10-06 14:07:25 -04:00
) -> Result < Option < ( DiffStatus , Option < String > ) > , Box < dyn std ::error ::Error > > {
Ok ( None )
}
2023-10-06 16:19:43 -04:00
/// Do no comparison.
///
/// This is for when you want to acknowledge that a field exists in the emacs token, but you do not have any validation for it when using the compare_properties!() macro. Ideally, this should be kept to a minimum since this represents untested values.
#[ allow(dead_code) ]
pub ( crate ) fn compare_identity ( ) -> ( ) {
( )
}
2023-10-06 18:30:08 -04:00
/// Assert that the emacs value is always nil or absent.
///
/// This is usually used for fields which, in my testing, are always nil. Using this compare function instead of simply doing a compare_noop will enable us to be alerted when we finally come across an org-mode document that has a value other than nil for the property.
pub ( crate ) fn compare_property_always_nil < ' b , ' s , ' x , R , RG > (
emacs : & ' b Token < ' s > ,
_rust_node : R ,
emacs_field : & ' x str ,
_rust_value_getter : RG ,
) -> Result < Option < ( DiffStatus , Option < String > ) > , Box < dyn std ::error ::Error > > {
let value = get_property ( emacs , emacs_field ) ? ;
if value . is_some ( ) {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} was expected to always be nil: {:?} " ,
emacs_field , value
) ) ;
Ok ( Some ( ( this_status , message ) ) )
} else {
Ok ( None )
}
}
2023-10-06 19:49:06 -04:00
pub ( crate ) fn compare_property_quoted_string <
' b ,
' s ,
' x ,
R ,
RV : AsRef < str > + std ::fmt ::Debug ,
RG : Fn ( R ) -> Option < RV > ,
> (
2023-10-06 13:40:11 -04:00
emacs : & ' b Token < ' s > ,
2023-10-06 14:07:25 -04:00
rust_node : R ,
2023-10-06 16:03:41 -04:00
emacs_field : & ' x str ,
2023-10-06 14:07:25 -04:00
rust_value_getter : RG ,
) -> Result < Option < ( DiffStatus , Option < String > ) > , Box < dyn std ::error ::Error > > {
let value = get_property_quoted_string ( emacs , emacs_field ) ? ;
let rust_value = rust_value_getter ( rust_node ) ;
2023-10-06 19:49:06 -04:00
if rust_value . as_ref ( ) . map ( | s | s . as_ref ( ) ) ! = value . as_ref ( ) . map ( String ::as_str ) {
2023-10-06 18:30:08 -04:00
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , value , rust_value
) ) ;
Ok ( Some ( ( this_status , message ) ) )
} else {
Ok ( None )
}
}
pub ( crate ) fn compare_property_unquoted_atom < ' b , ' s , ' x , R , RG : Fn ( R ) -> Option < & ' s str > > (
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
) -> Result < Option < ( DiffStatus , Option < String > ) > , Box < dyn std ::error ::Error > > {
let value = get_property_unquoted_atom ( emacs , emacs_field ) ? ;
let rust_value = rust_value_getter ( rust_node ) ;
if rust_value ! = value {
2023-10-06 14:07:25 -04:00
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , value , rust_value
) ) ;
Ok ( Some ( ( this_status , message ) ) )
} else {
Ok ( None )
}
}
2023-10-08 14:40:01 -04:00
pub ( crate ) fn compare_property_list_of_quoted_string <
' b ,
' s ,
' x ,
R ,
2023-10-08 15:08:21 -04:00
RV : AsRef < str > + std ::fmt ::Debug ,
RI : Iterator < Item = RV > ,
RG : Fn ( R ) -> Option < RI > ,
2023-10-08 14:40:01 -04:00
> (
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
) -> Result < Option < ( DiffStatus , Option < String > ) > , Box < dyn std ::error ::Error > > {
let value = get_property ( emacs , emacs_field ) ?
. map ( Token ::as_list )
. map_or ( Ok ( None ) , | r | r . map ( Some ) ) ? ;
let rust_value = rust_value_getter ( rust_node ) ;
2023-10-08 15:08:21 -04:00
// TODO: Seems we are needlessly coverting to a vec here.
let rust_value : Option < Vec < RV > > = rust_value . map ( | it | it . collect ( ) ) ;
match ( value , & rust_value ) {
2023-10-08 14:40:01 -04:00
( None , None ) = > { }
( None , Some ( _ ) ) | ( Some ( _ ) , None ) = > {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , value , rust_value
) ) ;
return Ok ( Some ( ( this_status , message ) ) ) ;
}
( Some ( el ) , Some ( rl ) ) if el . len ( ) ! = rl . len ( ) = > {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , value , rust_value
) ) ;
return Ok ( Some ( ( this_status , message ) ) ) ;
}
( Some ( el ) , Some ( rl ) ) = > {
for ( e , r ) in el . iter ( ) . zip ( rl ) {
let e = unquote ( e . as_atom ( ) ? ) ? ;
let r = r . as_ref ( ) ;
if e ! = r {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
2023-10-08 15:54:56 -04:00
" {} mismatch (emacs != rust) {:?} != {:?}. Full list: {:?} != {:?} " ,
emacs_field , e , r , value , rust_value
2023-10-08 14:40:01 -04:00
) ) ;
return Ok ( Some ( ( this_status , message ) ) ) ;
}
}
}
}
Ok ( None )
}