@@ -25,7 +25,7 @@ use crate::backtrace::Backtrace;
25
25
use crate :: borrow:: Cow ;
26
26
use crate :: cell;
27
27
use crate :: char;
28
- use crate :: fmt:: { self , Debug , Display } ;
28
+ use crate :: fmt:: { self , Debug , Display , Write } ;
29
29
use crate :: mem:: transmute;
30
30
use crate :: num;
31
31
use crate :: str;
@@ -807,3 +807,246 @@ impl dyn Error + Send + Sync {
807
807
} )
808
808
}
809
809
}
810
+
811
+ /// An error reporter that exposes the entire error chain for printing.
812
+ /// It also exposes options for formatting the error chain, either entirely on a single line,
813
+ /// or in multi-line format with each cause in the error chain on a new line.
814
+ ///
815
+ /// # Examples
816
+ ///
817
+ /// ```
818
+ /// #![feature(error_reporter)]
819
+ ///
820
+ /// use std::error::{Error, Report};
821
+ /// use std::fmt;
822
+ ///
823
+ /// #[derive(Debug)]
824
+ /// struct SuperError {
825
+ /// side: SuperErrorSideKick,
826
+ /// }
827
+ ///
828
+ /// impl fmt::Display for SuperError {
829
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
830
+ /// write!(f, "SuperError is here!")
831
+ /// }
832
+ /// }
833
+ ///
834
+ /// impl Error for SuperError {
835
+ /// fn source(&self) -> Option<&(dyn Error + 'static)> {
836
+ /// Some(&self.side)
837
+ /// }
838
+ /// }
839
+ ///
840
+ /// #[derive(Debug)]
841
+ /// struct SuperErrorSideKick;
842
+ ///
843
+ /// impl fmt::Display for SuperErrorSideKick {
844
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
845
+ /// write!(f, "SuperErrorSideKick is here!")
846
+ /// }
847
+ /// }
848
+ ///
849
+ /// impl Error for SuperErrorSideKick {}
850
+ ///
851
+ /// fn main() {
852
+ /// let error = SuperError { side: SuperErrorSideKick };
853
+ /// let report = Report::new(&error).pretty();
854
+ ///
855
+ /// println!("{}", report);
856
+ /// }
857
+ /// ```
858
+ #[ unstable( feature = "error_reporter" , issue = "90172" ) ]
859
+ pub struct Report < E > {
860
+ source : E ,
861
+ show_backtrace : bool ,
862
+ pretty : bool ,
863
+ }
864
+
865
+ impl < E > Report < E >
866
+ where
867
+ E : Error ,
868
+ {
869
+ /// Create a new `Report` from an input error.
870
+ #[ unstable( feature = "error_reporter" , issue = "90172" ) ]
871
+ pub fn new ( source : E ) -> Report < E > {
872
+ Report { source, show_backtrace : false , pretty : false }
873
+ }
874
+
875
+ /// Enable pretty-printing the report.
876
+ #[ unstable( feature = "error_reporter" , issue = "90172" ) ]
877
+ pub fn pretty ( mut self ) -> Self {
878
+ self . pretty = true ;
879
+ self
880
+ }
881
+
882
+ /// Enable showing a backtrace for the report.
883
+ #[ unstable( feature = "error_reporter" , issue = "90172" ) ]
884
+ pub fn show_backtrace ( mut self ) -> Self {
885
+ self . show_backtrace = true ;
886
+ self
887
+ }
888
+
889
+ /// Format the report as a single line.
890
+ #[ unstable( feature = "error_reporter" , issue = "90172" ) ]
891
+ fn fmt_singleline ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
892
+ write ! ( f, "{}" , self . source) ?;
893
+
894
+ let sources = self . source . source ( ) . into_iter ( ) . flat_map ( <dyn Error >:: chain) ;
895
+
896
+ for cause in sources {
897
+ write ! ( f, ": {}" , cause) ?;
898
+ }
899
+
900
+ Ok ( ( ) )
901
+ }
902
+
903
+ /// Format the report as multiple lines, with each error cause on its own line.
904
+ #[ unstable( feature = "error_reporter" , issue = "90172" ) ]
905
+ fn fmt_multiline ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
906
+ let error = & self . source ;
907
+
908
+ write ! ( f, "{}" , error) ?;
909
+
910
+ if let Some ( cause) = error. source ( ) {
911
+ write ! ( f, "\n \n Caused by:" ) ?;
912
+
913
+ let multiple = cause. source ( ) . is_some ( ) ;
914
+ let format = if multiple {
915
+ Format :: Numbered { ind : 0 }
916
+ } else {
917
+ Format :: Uniform { indentation : " " }
918
+ } ;
919
+
920
+ for error in cause. chain ( ) {
921
+ writeln ! ( f) ?;
922
+
923
+ let mut indented = Indented { inner : f, needs_indent : true , format } ;
924
+
925
+ write ! ( indented, "{}" , error) ?;
926
+ }
927
+ }
928
+
929
+ if self . show_backtrace {
930
+ let backtrace = error. backtrace ( ) ;
931
+
932
+ if let Some ( backtrace) = backtrace {
933
+ let mut backtrace = backtrace. to_string ( ) ;
934
+
935
+ write ! ( f, "\n \n " ) ?;
936
+ writeln ! ( f, "Stack backtrace:" ) ?;
937
+
938
+ backtrace. truncate ( backtrace. trim_end ( ) . len ( ) ) ;
939
+
940
+ write ! ( f, "{}" , backtrace) ?;
941
+ }
942
+ }
943
+
944
+ Ok ( ( ) )
945
+ }
946
+ }
947
+
948
+ #[ unstable( feature = "error_reporter" , issue = "90172" ) ]
949
+ impl < E > From < E > for Report < E >
950
+ where
951
+ E : Error ,
952
+ {
953
+ fn from ( source : E ) -> Self {
954
+ Report :: new ( source)
955
+ }
956
+ }
957
+
958
+ #[ unstable( feature = "error_reporter" , issue = "90172" ) ]
959
+ impl < E > fmt:: Display for Report < E >
960
+ where
961
+ E : Error ,
962
+ {
963
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
964
+ if self . pretty { self . fmt_multiline ( f) } else { self . fmt_singleline ( f) }
965
+ }
966
+ }
967
+
968
+ // This type intentionally outputs the same format for `Display` and `Debug`for
969
+ // situations where you unwrap a `Report` or return it from main.
970
+ #[ unstable( feature = "error_reporter" , issue = "90172" ) ]
971
+ impl < E > fmt:: Debug for Report < E >
972
+ where
973
+ E : Error ,
974
+ {
975
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
976
+ fmt:: Display :: fmt ( self , f)
977
+ }
978
+ }
979
+
980
+ /// Encapsulates how error sources are indented and formatted.
981
+ struct Indented < ' a , D : ?Sized > {
982
+ inner : & ' a mut D ,
983
+ needs_indent : bool ,
984
+ format : Format ,
985
+ }
986
+
987
+ /// The possible variants that error sources can be formatted as.
988
+ #[ derive( Clone , Copy ) ]
989
+ enum Format {
990
+ /// Insert uniform indentation before every line.
991
+ ///
992
+ /// This format takes a static string as input and inserts it after every newline.
993
+ Uniform {
994
+ /// The string to insert as indentation.
995
+ indentation : & ' static str ,
996
+ } ,
997
+ /// Inserts a number before the first line.
998
+ ///
999
+ /// This format hard codes the indentation level to match the indentation from
1000
+ /// `std::backtrace::Backtrace`.
1001
+ Numbered {
1002
+ /// The index to insert before the first line of output.
1003
+ ind : usize ,
1004
+ } ,
1005
+ }
1006
+
1007
+ impl < D > Write for Indented < ' _ , D >
1008
+ where
1009
+ D : Write + ?Sized ,
1010
+ {
1011
+ fn write_str ( & mut self , s : & str ) -> fmt:: Result {
1012
+ for ( ind, line) in s. split ( '\n' ) . enumerate ( ) {
1013
+ if ind > 0 {
1014
+ self . inner . write_char ( '\n' ) ?;
1015
+ self . needs_indent = true ;
1016
+ }
1017
+
1018
+ if self . needs_indent {
1019
+ if line. is_empty ( ) {
1020
+ continue ;
1021
+ }
1022
+
1023
+ self . format . insert_indentation ( ind, & mut self . inner ) ?;
1024
+ self . needs_indent = false ;
1025
+ }
1026
+
1027
+ self . inner . write_fmt ( format_args ! ( "{}" , line) ) ?;
1028
+ }
1029
+
1030
+ Ok ( ( ) )
1031
+ }
1032
+ }
1033
+
1034
+ impl Format {
1035
+ /// Write the specified formatting to the write buffer.
1036
+ fn insert_indentation ( & mut self , line : usize , f : & mut dyn Write ) -> fmt:: Result {
1037
+ match self {
1038
+ Format :: Uniform { indentation } => {
1039
+ write ! ( f, "{}" , indentation)
1040
+ }
1041
+ Format :: Numbered { ind } => {
1042
+ if line == 0 {
1043
+ write ! ( f, "{: >4}: " , ind) ?;
1044
+ * ind += 1 ;
1045
+ Ok ( ( ) )
1046
+ } else {
1047
+ write ! ( f, " " )
1048
+ }
1049
+ }
1050
+ }
1051
+ }
1052
+ }
0 commit comments