2023-10-10 00:05:34 -04:00
use std ::collections ::BTreeSet ;
2023-10-06 14:07:25 -04:00
use std ::fmt ::Debug ;
2023-10-09 21:04:41 -04:00
use std ::str ::FromStr ;
2023-10-06 14:07:25 -04:00
2023-10-09 15:13:05 -04:00
use super ::diff ::artificial_diff_scope ;
2023-10-11 14:03:42 -04:00
use super ::diff ::artificial_owned_diff_scope ;
2023-10-09 15:13:05 -04:00
use super ::diff ::compare_ast_node ;
use super ::diff ::DiffEntry ;
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-09 21:04:41 -04:00
use super ::util ::get_property_numeric ;
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-09 15:13:05 -04:00
use crate ::types ::AstNode ;
2023-10-10 00:43:02 -04:00
use crate ::types ::CharOffsetInLine ;
use crate ::types ::LineNumber ;
2023-10-11 13:55:43 -04:00
use crate ::types ::Object ;
2023-10-10 00:43:02 -04:00
use crate ::types ::RetainLabels ;
use crate ::types ::SwitchNumberLines ;
2023-10-06 13:40:11 -04:00
#[ derive(Debug) ]
pub ( crate ) enum EmacsField < ' s > {
Required ( & ' s str ) ,
Optional ( & ' s str ) ,
}
2023-10-09 15:13:05 -04:00
#[ derive(Debug) ]
pub ( crate ) enum ComparePropertiesResult < ' b , ' s > {
NoChange ,
/// Return when you want the status for "this" node to change (as opposed to collecting child status).
SelfChange ( DiffStatus , Option < String > ) ,
DiffEntry ( DiffEntry < ' b , ' s > ) ,
}
2023-10-10 17:40:27 -04:00
impl < ' b , ' s > ComparePropertiesResult < ' b , ' s > {
pub ( crate ) fn apply (
self ,
child_status : & mut Vec < DiffEntry < ' b , ' s > > ,
this_status : & mut DiffStatus ,
message : & mut Option < String > ,
) {
match self {
ComparePropertiesResult ::NoChange = > { }
ComparePropertiesResult ::SelfChange ( new_status , new_message ) = > {
* this_status = new_status ;
* message = new_message
}
ComparePropertiesResult ::DiffEntry ( diff_entry ) = > child_status . push ( diff_entry ) ,
}
// foo
}
}
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.
2023-10-06 16:32:49 -04:00
pub ( crate ) fn compare_noop < ' b , ' s , ' x , R , RG > (
2023-10-09 15:13:05 -04:00
_source : & ' s str ,
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-09 15:13:05 -04:00
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error > > {
Ok ( ComparePropertiesResult ::NoChange )
2023-10-06 14:07:25 -04:00
}
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.
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 > (
2023-10-09 15:13:05 -04:00
_source : & ' s str ,
2023-10-06 18:30:08 -04:00
emacs : & ' b Token < ' s > ,
_rust_node : R ,
emacs_field : & ' x str ,
_rust_value_getter : RG ,
2023-10-09 15:13:05 -04:00
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error > > {
2023-10-06 18:30:08 -04:00
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
) ) ;
2023-10-09 15:13:05 -04:00
Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) )
2023-10-06 18:30:08 -04:00
} else {
2023-10-09 15:13:05 -04:00
Ok ( ComparePropertiesResult ::NoChange )
2023-10-06 18:30:08 -04:00
}
}
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-09 15:13:05 -04:00
_source : & ' s str ,
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 ,
2023-10-09 15:13:05 -04:00
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error > > {
2023-10-06 14:07:25 -04:00
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
) ) ;
2023-10-09 15:13:05 -04:00
Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) )
2023-10-06 18:30:08 -04:00
} else {
2023-10-09 15:13:05 -04:00
Ok ( ComparePropertiesResult ::NoChange )
2023-10-06 18:30:08 -04:00
}
}
pub ( crate ) fn compare_property_unquoted_atom < ' b , ' s , ' x , R , RG : Fn ( R ) -> Option < & ' s str > > (
2023-10-09 15:13:05 -04:00
_source : & ' s str ,
2023-10-06 18:30:08 -04:00
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
2023-10-09 15:13:05 -04:00
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error > > {
2023-10-06 18:30:08 -04:00
let value = get_property_unquoted_atom ( emacs , emacs_field ) ? ;
let rust_value = rust_value_getter ( rust_node ) ;
2023-10-09 21:04:41 -04:00
if rust_value ! = value {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , value , rust_value
) ) ;
Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) )
} else {
Ok ( ComparePropertiesResult ::NoChange )
}
}
pub ( crate ) fn compare_property_numeric <
' b ,
' s ,
' x ,
R ,
RV : FromStr + PartialEq + Debug ,
RG : Fn ( R ) -> Option < RV > ,
> (
_source : & ' s str ,
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error + ' s > >
where
< RV as FromStr > ::Err : std ::error ::Error ,
< RV as FromStr > ::Err : ' s ,
{
let value = get_property_numeric ::< RV > ( emacs , emacs_field ) ? ;
let rust_value = rust_value_getter ( rust_node ) ;
2023-10-06 18:30:08 -04:00
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
) ) ;
2023-10-09 15:13:05 -04:00
Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) )
2023-10-06 14:07:25 -04:00
} else {
2023-10-09 15:13:05 -04:00
Ok ( ComparePropertiesResult ::NoChange )
2023-10-06 14:07:25 -04:00
}
}
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
> (
2023-10-09 15:13:05 -04:00
_source : & ' s str ,
2023-10-08 14:40:01 -04:00
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
2023-10-09 15:13:05 -04:00
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error > > {
2023-10-08 14:40:01 -04:00
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
) ) ;
2023-10-09 15:13:05 -04:00
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
2023-10-08 14:40:01 -04:00
}
( 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
) ) ;
2023-10-09 15:13:05 -04:00
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
2023-10-08 14:40:01 -04:00
}
( 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
) ) ;
2023-10-09 15:13:05 -04:00
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
2023-10-08 14:40:01 -04:00
}
}
}
}
2023-10-09 15:13:05 -04:00
Ok ( ComparePropertiesResult ::NoChange )
2023-10-08 14:40:01 -04:00
}
2023-10-08 18:14:48 -04:00
2023-10-10 00:05:34 -04:00
pub ( crate ) fn compare_property_set_of_quoted_string <
' a ,
' b ,
' s ,
' x ,
R ,
RV : AsRef < str > + std ::fmt ::Debug + Ord + ' a + ? Sized ,
RI : Iterator < Item = & ' a RV > ,
RG : Fn ( R ) -> Option < RI > ,
> (
_source : & ' s str ,
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
) -> Result < ComparePropertiesResult < ' b , ' s > , 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 empty = Vec ::new ( ) ;
let value = value . unwrap_or ( & empty ) ;
let rust_value = rust_value_getter ( rust_node ) ;
let rust_value = if let Some ( rust_value ) = rust_value {
let slices : BTreeSet < & str > = rust_value . map ( | rv | rv . as_ref ( ) ) . collect ( ) ;
slices
} else {
BTreeSet ::new ( )
} ;
let value : Vec < & str > = value
. iter ( )
. map ( | e | e . as_atom ( ) )
. collect ::< Result < Vec < _ > , _ > > ( ) ? ;
let value : Vec < String > = value
. into_iter ( )
. map ( unquote )
. collect ::< Result < Vec < _ > , _ > > ( ) ? ;
let value : BTreeSet < & str > = value . iter ( ) . map ( | e | e . as_str ( ) ) . collect ( ) ;
let mismatched : Vec < _ > = value
. symmetric_difference ( & rust_value )
. map ( | val | * val )
. collect ( ) ;
if ! mismatched . is_empty ( ) {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch. Mismatched values: {} " ,
emacs_field ,
mismatched . join ( " , " )
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
}
Ok ( ComparePropertiesResult ::NoChange )
}
2023-10-08 18:14:48 -04:00
pub ( crate ) fn compare_property_boolean < ' b , ' s , ' x , R , RG : Fn ( R ) -> bool > (
2023-10-09 15:13:05 -04:00
_source : & ' s str ,
2023-10-08 18:14:48 -04:00
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
2023-10-09 15:13:05 -04:00
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error > > {
2023-10-08 18:14:48 -04:00
// get_property already converts nil to None.
let value = get_property ( emacs , emacs_field ) ? . is_some ( ) ;
let rust_value = rust_value_getter ( rust_node ) ;
if rust_value ! = value {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , value , rust_value
) ) ;
2023-10-09 15:13:05 -04:00
Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) )
2023-10-08 18:14:48 -04:00
} else {
2023-10-09 15:13:05 -04:00
Ok ( ComparePropertiesResult ::NoChange )
}
}
2023-10-09 21:27:18 -04:00
pub ( crate ) fn compare_property_single_ast_node <
' b ,
' s ,
' x : ' b + ' s ,
R ,
RV : std ::fmt ::Debug ,
RG : Fn ( R ) -> Option < RV > ,
> (
source : & ' s str ,
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error > >
where
AstNode < ' b , ' s > : From < RV > ,
{
let value = get_property ( emacs , emacs_field ) ? ;
let rust_value = rust_value_getter ( rust_node ) ;
match ( value , rust_value ) {
( None , None ) = > { }
( None , rv @ Some ( _ ) ) | ( Some ( _ ) , rv @ None ) = > {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , value , rv
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
}
( Some ( ev ) , Some ( rv ) ) = > {
let child_status : Vec < DiffEntry < ' b , ' s > > =
vec! [ compare_ast_node ( source , ev , rv . into ( ) ) ? ] ;
let diff_scope = artificial_diff_scope ( emacs_field , child_status ) ? ;
return Ok ( ComparePropertiesResult ::DiffEntry ( diff_scope ) ) ;
}
}
Ok ( ComparePropertiesResult ::NoChange )
}
2023-10-09 15:13:05 -04:00
pub ( crate ) fn compare_property_list_of_ast_nodes <
' b ,
' s ,
' x : ' b + ' s ,
R ,
RV : std ::fmt ::Debug ,
RI : Iterator < Item = RV > ,
RG : Fn ( R ) -> Option < RI > ,
> (
source : & ' s str ,
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error > >
where
AstNode < ' b , ' s > : From < RV > ,
{
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 ) ;
// 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 ) {
( None , None ) = > { }
2023-10-10 16:33:17 -04:00
( Some ( el ) , None )
if el . len ( ) = = 1
& & el . into_iter ( ) . all ( | t | {
if let Ok ( r # """"# ) = t . as_atom ( ) {
true
} else {
false
}
} ) = > { }
2023-10-09 15:13:05 -04:00
( None , rv @ Some ( _ ) ) | ( Some ( _ ) , rv @ None ) = > {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , value , rv
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( 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 , el , rl
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
}
( Some ( el ) , Some ( rl ) ) = > {
let mut child_status : Vec < DiffEntry < ' b , ' s > > = Vec ::with_capacity ( rl . len ( ) ) ;
for ( e , r ) in el . iter ( ) . zip ( rl ) {
child_status . push ( compare_ast_node ( source , e , r . into ( ) ) ? ) ;
}
let diff_scope = artificial_diff_scope ( emacs_field , child_status ) ? ;
return Ok ( ComparePropertiesResult ::DiffEntry ( diff_scope ) ) ;
}
2023-10-08 18:14:48 -04:00
}
2023-10-09 15:13:05 -04:00
Ok ( ComparePropertiesResult ::NoChange )
2023-10-08 18:14:48 -04:00
}
2023-10-10 00:43:02 -04:00
2023-10-11 13:55:43 -04:00
/// Special compare used for affiliate keywords that are parsed as objects.
///
/// Org-mode seems to store these as a 3-deep list:
/// - Outer list with 1 element per #+caption keyword (or other parsed keyword).
/// - Middle list that seems to always have 1 element.
/// - Inner list of the objects from each #+caption keyword (or other parsed keyword).
pub ( crate ) fn compare_property_list_of_list_of_list_of_ast_nodes <
' b ,
' s ,
2023-10-11 14:03:42 -04:00
' x ,
2023-10-11 13:55:43 -04:00
R ,
RG : Fn ( R ) -> Option < & ' b Vec < Vec < Object < ' s > > > > ,
> (
source : & ' s str ,
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error > > {
let rust_value = rust_value_getter ( rust_node ) ;
let value = get_property ( emacs , emacs_field ) ?
. map ( Token ::as_list )
. map_or ( Ok ( None ) , | r | r . map ( Some ) ) ? ;
let ( value , rust_value ) = match ( value , rust_value ) {
( None , None ) = > {
return Ok ( ComparePropertiesResult ::NoChange ) ;
}
( None , Some ( _ ) ) | ( Some ( _ ) , None ) = > {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , value , rust_value
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
}
( Some ( value ) , Some ( rust_value ) ) if value . len ( ) ! = rust_value . len ( ) = > {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , value , rust_value
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
}
( Some ( value ) , Some ( rust_value ) ) = > ( value , rust_value ) ,
} ;
// Iterate the outer lists
for ( value , rust_value ) in value . iter ( ) . zip ( rust_value . iter ( ) ) {
// Assert the middle list is a length of 1 because I've never seen it any other way.
let value = value . as_list ( ) ? ;
if value . len ( ) ! = 1 {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , value , rust_value
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
}
// Drill past the middle list to the inner list.
let value = value
. first ( )
. expect ( " The above if-statement asserts this exists. " ) ;
let value = value . as_list ( ) ? ;
// Compare inner lists
let mut child_status : Vec < DiffEntry < ' b , ' s > > = Vec ::with_capacity ( rust_value . len ( ) ) ;
for ( e , r ) in value . iter ( ) . zip ( rust_value ) {
child_status . push ( compare_ast_node ( source , e , r . into ( ) ) ? ) ;
}
2023-10-11 14:03:42 -04:00
let diff_scope = artificial_owned_diff_scope ( emacs_field , child_status ) ? ;
return Ok ( ComparePropertiesResult ::DiffEntry ( diff_scope ) ) ;
2023-10-11 13:55:43 -04:00
}
Ok ( ComparePropertiesResult ::NoChange )
}
2023-10-10 00:43:02 -04:00
pub ( crate ) fn compare_property_number_lines <
' b ,
' s ,
' x ,
' y ,
R ,
RG : Fn ( R ) -> Option < & ' y SwitchNumberLines > ,
> (
_source : & ' s str ,
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error > > {
let number_lines = get_property ( emacs , emacs_field ) ? ;
let rust_value = rust_value_getter ( rust_node ) ;
match ( number_lines , & rust_value ) {
( None , None ) = > { }
( Some ( number_lines ) , Some ( rust_number_lines ) ) = > {
let token_list = number_lines . as_list ( ) ? ;
let number_type = token_list
. get ( 0 )
. map ( Token ::as_atom )
. map_or ( Ok ( None ) , | r | r . map ( Some ) ) ?
. ok_or ( " :number-lines should have a type. " ) ? ;
let number_value = token_list
. get ( 2 )
. map ( Token ::as_atom )
. map_or ( Ok ( None ) , | r | r . map ( Some ) ) ?
. map ( | val | val . parse ::< LineNumber > ( ) )
. map_or ( Ok ( None ) , | r | r . map ( Some ) ) ?
. ok_or ( " :number-lines should have a value. " ) ? ;
match ( number_type , number_value , rust_number_lines ) {
( " new " , emacs_val , SwitchNumberLines ::New ( rust_val ) ) if emacs_val = = * rust_val = > { }
( " continued " , emacs_val , SwitchNumberLines ::Continued ( rust_val ) )
if emacs_val = = * rust_val = > { }
_ = > {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , number_lines , rust_value
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
}
}
}
_ = > {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , number_lines , rust_value
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
}
} ;
Ok ( ComparePropertiesResult ::NoChange )
}
pub ( crate ) fn compare_property_retain_labels < ' b , ' s , ' x , ' y , R , RG : Fn ( R ) -> & ' y RetainLabels > (
_source : & ' s str ,
emacs : & ' b Token < ' s > ,
rust_node : R ,
emacs_field : & ' x str ,
rust_value_getter : RG ,
) -> Result < ComparePropertiesResult < ' b , ' s > , Box < dyn std ::error ::Error + ' s > > {
let rust_value = rust_value_getter ( rust_node ) ;
let retain_labels = get_property_unquoted_atom ( emacs , " :retain-labels " ) ? ;
if let Some ( retain_labels ) = retain_labels {
if retain_labels = = " t " {
match rust_value {
RetainLabels ::Yes = > { }
_ = > {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , retain_labels , rust_value
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
}
}
} else {
let retain_labels : CharOffsetInLine = get_property_numeric ( emacs , " :retain-labels " ) ? . expect ( " Cannot be None or else the earlier get_property_unquoted_atom would have been None. " ) ;
match ( retain_labels , rust_value ) {
( e , RetainLabels ::Keep ( r ) ) if e = = * r = > { }
_ = > {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , retain_labels , rust_value
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
}
}
}
} else {
match rust_value {
RetainLabels ::No = > { }
_ = > {
let this_status = DiffStatus ::Bad ;
let message = Some ( format! (
" {} mismatch (emacs != rust) {:?} != {:?} " ,
emacs_field , retain_labels , rust_value
) ) ;
return Ok ( ComparePropertiesResult ::SelfChange ( this_status , message ) ) ;
}
}
}
Ok ( ComparePropertiesResult ::NoChange )
}