@@ -342,6 +342,19 @@ impl core::ops::Deref for StringOrToken {
342342 }
343343}
344344
345+ #[ cfg( feature = "miette" ) ]
346+ impl miette:: SourceCode for StringOrToken {
347+ fn read_span < ' a > (
348+ & ' a self ,
349+ span : & miette:: SourceSpan ,
350+ context_lines_before : usize ,
351+ context_lines_after : usize ,
352+ ) -> Result < Box < dyn miette:: SpanContents < ' a > + ' a > , miette:: MietteError > {
353+ let s: & str = & * * self ;
354+ s. read_span ( span, context_lines_before, context_lines_after)
355+ }
356+ }
357+
345358impl Diagnostic for ParseIndexError {
346359 type Subject = StringOrToken ;
347360
@@ -368,8 +381,8 @@ impl Diagnostic for ParseIndexError {
368381 let len = subject
369382 . chars ( )
370383 . skip ( err. offset )
371- . position ( |c| ! c. is_ascii_digit ( ) )
372- . expect ( "at least one non-digit char" ) ;
384+ . position ( |c| c. is_ascii_digit ( ) )
385+ . unwrap_or ( subject . len ( ) ) ;
373386 let text = String :: from ( "invalid character(s)" ) ;
374387 Some ( Box :: new ( once ( Label :: new ( text, err. offset , len) ) ) )
375388 }
@@ -432,7 +445,7 @@ impl std::error::Error for InvalidCharacterError {}
432445#[ cfg( test) ]
433446mod tests {
434447 use super :: * ;
435- use crate :: Token ;
448+ use crate :: { Diagnose , Token } ;
436449
437450 #[ test]
438451 fn index_from_usize ( ) {
@@ -522,4 +535,66 @@ mod tests {
522535 let index = Index :: try_from ( & token) . unwrap ( ) ;
523536 assert_eq ! ( index, Index :: Next ) ;
524537 }
538+
539+ #[ test]
540+ fn diagnose_works_with_token_or_string ( ) {
541+ let token = Token :: new ( "foo" ) ;
542+ // despite the clone, this is cheap because `token` is borrowed
543+ Index :: try_from ( token. clone ( ) ) . diagnose ( token) . unwrap_err ( ) ;
544+ let s = String :: from ( "bar" ) ;
545+ Index :: try_from ( & s) . diagnose ( s) . unwrap_err ( ) ;
546+ }
547+
548+ #[ test]
549+ fn error_from_invalid_chars ( ) {
550+ let s = String :: from ( "bar" ) ;
551+ let err = Index :: try_from ( & s) . diagnose ( s) . unwrap_err ( ) ;
552+
553+ #[ cfg( feature = "miette" ) ]
554+ {
555+ let labels: Vec < _ > = miette:: Diagnostic :: labels ( & err)
556+ . unwrap ( )
557+ . into_iter ( )
558+ . collect ( ) ;
559+ assert_eq ! (
560+ labels,
561+ vec![ miette:: LabeledSpan :: new(
562+ Some ( "invalid character(s)" . into( ) ) ,
563+ 0 ,
564+ 3
565+ ) ]
566+ ) ;
567+ }
568+
569+ let ( src, sub) = err. decompose ( ) ;
570+ let labels: Vec < _ > = src. labels ( & sub) . unwrap ( ) . into_iter ( ) . collect ( ) ;
571+
572+ assert_eq ! (
573+ labels,
574+ vec![ Label :: new( "invalid character(s)" . into( ) , 0 , 3 ) ]
575+ ) ;
576+ }
577+
578+ #[ test]
579+ fn error_from_leading_zeros ( ) {
580+ let s = String :: from ( "000001" ) ;
581+ let err = Index :: try_from ( & s) . diagnose ( s) . unwrap_err ( ) ;
582+
583+ #[ cfg( feature = "miette" ) ]
584+ {
585+ let labels: Vec < _ > = miette:: Diagnostic :: labels ( & err)
586+ . unwrap ( )
587+ . into_iter ( )
588+ . collect ( ) ;
589+ assert_eq ! (
590+ labels,
591+ vec![ miette:: LabeledSpan :: new( Some ( "leading zeros" . into( ) ) , 0 , 5 ) ]
592+ ) ;
593+ }
594+
595+ let ( src, sub) = err. decompose ( ) ;
596+ let labels: Vec < _ > = src. labels ( & sub) . unwrap ( ) . into_iter ( ) . collect ( ) ;
597+
598+ assert_eq ! ( labels, vec![ Label :: new( "leading zeros" . into( ) , 0 , 5 ) ] ) ;
599+ }
525600}
0 commit comments