@@ -25,7 +25,7 @@ use crate::backtrace::Backtrace;
2525use crate :: borrow:: Cow ;
2626use crate :: cell;
2727use crate :: char;
28- use crate :: fmt:: { self , Debug , Display } ;
28+ use crate :: fmt:: { self , Debug , Display , Write } ;
2929use crate :: mem:: transmute;
3030use crate :: num;
3131use crate :: str;
@@ -807,3 +807,246 @@ impl dyn Error + Send + Sync {
807807 } )
808808 }
809809}
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