@@ -35,7 +35,17 @@ const ENCODING_SET: &AsciiSet = &CONTROLS
35
35
/// assert_eq!(status1.code(), status2.code());
36
36
/// ```
37
37
#[ derive( Clone ) ]
38
- pub struct Status {
38
+ pub struct Status ( Box < StatusInner > ) ;
39
+
40
+ impl From < StatusInner > for Status {
41
+ fn from ( value : StatusInner ) -> Self {
42
+ Self ( Box :: new ( value) )
43
+ }
44
+ }
45
+
46
+ /// Box the contents of Status to avoid large error variants
47
+ #[ derive( Clone ) ]
48
+ struct StatusInner {
39
49
/// The gRPC status code, found in the `grpc-status` header.
40
50
code : Code ,
41
51
/// A relevant error message, found in the `grpc-message` header.
@@ -160,13 +170,14 @@ impl std::fmt::Display for Code {
160
170
impl Status {
161
171
/// Create a new `Status` with the associated code and message.
162
172
pub fn new ( code : Code , message : impl Into < String > ) -> Status {
163
- Status {
173
+ StatusInner {
164
174
code,
165
175
message : message. into ( ) ,
166
176
details : Bytes :: new ( ) ,
167
177
metadata : MetadataMap :: new ( ) ,
168
178
source : None ,
169
179
}
180
+ . into ( )
170
181
}
171
182
172
183
/// The operation completed successfully.
@@ -318,7 +329,7 @@ impl Status {
318
329
pub fn from_error ( err : Box < dyn Error + Send + Sync + ' static > ) -> Status {
319
330
Status :: try_from_error ( err) . unwrap_or_else ( |err| {
320
331
let mut status = Status :: new ( Code :: Unknown , err. to_string ( ) ) ;
321
- status. source = Some ( err. into ( ) ) ;
332
+ status. 0 . source = Some ( err. into ( ) ) ;
322
333
status
323
334
} )
324
335
}
@@ -349,7 +360,7 @@ impl Status {
349
360
} ;
350
361
351
362
if let Some ( mut status) = find_status_in_source_chain ( & * err) {
352
- status. source = Some ( err. into ( ) ) ;
363
+ status. 0 . source = Some ( err. into ( ) ) ;
353
364
return Ok ( status) ;
354
365
}
355
366
@@ -362,7 +373,7 @@ impl Status {
362
373
let code = Self :: code_from_h2 ( & err) ;
363
374
364
375
let mut status = Self :: new ( code, format ! ( "h2 protocol error: {err}" ) ) ;
365
- status. source = Some ( Arc :: new ( * err) ) ;
376
+ status. 0 . source = Some ( Arc :: new ( * err) ) ;
366
377
status
367
378
}
368
379
@@ -389,7 +400,7 @@ impl Status {
389
400
#[ cfg( feature = "server" ) ]
390
401
fn to_h2_error ( & self ) -> h2:: Error {
391
402
// conservatively transform to h2 error codes...
392
- let reason = match self . code {
403
+ let reason = match self . code ( ) {
393
404
Code :: Cancelled => h2:: Reason :: CANCEL ,
394
405
_ => h2:: Reason :: INTERNAL_ERROR ,
395
406
} ;
@@ -473,53 +484,56 @@ impl Status {
473
484
}
474
485
} ;
475
486
476
- Some ( Status {
477
- code,
478
- message,
479
- details,
480
- metadata : MetadataMap :: from_headers ( other_headers) ,
481
- source : None ,
482
- } )
487
+ Some (
488
+ StatusInner {
489
+ code,
490
+ message,
491
+ details,
492
+ metadata : MetadataMap :: from_headers ( other_headers) ,
493
+ source : None ,
494
+ }
495
+ . into ( ) ,
496
+ )
483
497
}
484
498
485
499
/// Get the gRPC `Code` of this `Status`.
486
500
pub fn code ( & self ) -> Code {
487
- self . code
501
+ self . 0 . code
488
502
}
489
503
490
504
/// Get the text error message of this `Status`.
491
505
pub fn message ( & self ) -> & str {
492
- & self . message
506
+ & self . 0 . message
493
507
}
494
508
495
509
/// Get the opaque error details of this `Status`.
496
510
pub fn details ( & self ) -> & [ u8 ] {
497
- & self . details
511
+ & self . 0 . details
498
512
}
499
513
500
514
/// Get a reference to the custom metadata.
501
515
pub fn metadata ( & self ) -> & MetadataMap {
502
- & self . metadata
516
+ & self . 0 . metadata
503
517
}
504
518
505
519
/// Get a mutable reference to the custom metadata.
506
520
pub fn metadata_mut ( & mut self ) -> & mut MetadataMap {
507
- & mut self . metadata
521
+ & mut self . 0 . metadata
508
522
}
509
523
510
524
pub ( crate ) fn to_header_map ( & self ) -> Result < HeaderMap , Self > {
511
- let mut header_map = HeaderMap :: with_capacity ( 3 + self . metadata . len ( ) ) ;
525
+ let mut header_map = HeaderMap :: with_capacity ( 3 + self . 0 . metadata . len ( ) ) ;
512
526
self . add_header ( & mut header_map) ?;
513
527
Ok ( header_map)
514
528
}
515
529
516
530
/// Add headers from this `Status` into `header_map`.
517
531
pub fn add_header ( & self , header_map : & mut HeaderMap ) -> Result < ( ) , Self > {
518
- header_map. extend ( self . metadata . clone ( ) . into_sanitized_headers ( ) ) ;
532
+ header_map. extend ( self . 0 . metadata . clone ( ) . into_sanitized_headers ( ) ) ;
519
533
520
- header_map. insert ( Self :: GRPC_STATUS , self . code . to_header_value ( ) ) ;
534
+ header_map. insert ( Self :: GRPC_STATUS , self . 0 . code . to_header_value ( ) ) ;
521
535
522
- if !self . message . is_empty ( ) {
536
+ if !self . 0 . message . is_empty ( ) {
523
537
let to_write = Bytes :: copy_from_slice (
524
538
Cow :: from ( percent_encode ( self . message ( ) . as_bytes ( ) , ENCODING_SET ) ) . as_bytes ( ) ,
525
539
) ;
@@ -530,8 +544,8 @@ impl Status {
530
544
) ;
531
545
}
532
546
533
- if !self . details . is_empty ( ) {
534
- let details = crate :: util:: base64:: STANDARD_NO_PAD . encode ( & self . details [ ..] ) ;
547
+ if !self . 0 . details . is_empty ( ) {
548
+ let details = crate :: util:: base64:: STANDARD_NO_PAD . encode ( & self . 0 . details [ ..] ) ;
535
549
536
550
header_map. insert (
537
551
Self :: GRPC_STATUS_DETAILS ,
@@ -559,18 +573,19 @@ impl Status {
559
573
details : Bytes ,
560
574
metadata : MetadataMap ,
561
575
) -> Status {
562
- Status {
576
+ StatusInner {
563
577
code,
564
578
message : message. into ( ) ,
565
579
details,
566
580
metadata,
567
581
source : None ,
568
582
}
583
+ . into ( )
569
584
}
570
585
571
586
/// Add a source error to this status.
572
587
pub fn set_source ( & mut self , source : Arc < dyn Error + Send + Sync + ' static > ) -> & mut Status {
573
- self . source = Some ( source) ;
588
+ self . 0 . source = Some ( source) ;
574
589
self
575
590
}
576
591
@@ -598,15 +613,18 @@ fn find_status_in_source_chain(err: &(dyn Error + 'static)) -> Option<Status> {
598
613
599
614
while let Some ( err) = source {
600
615
if let Some ( status) = err. downcast_ref :: < Status > ( ) {
601
- return Some ( Status {
602
- code : status. code ,
603
- message : status. message . clone ( ) ,
604
- details : status. details . clone ( ) ,
605
- metadata : status. metadata . clone ( ) ,
606
- // Since `Status` is not `Clone`, any `source` on the original Status
607
- // cannot be cloned so must remain with the original `Status`.
608
- source : None ,
609
- } ) ;
616
+ return Some (
617
+ StatusInner {
618
+ code : status. 0 . code ,
619
+ message : status. 0 . message . clone ( ) ,
620
+ details : status. 0 . details . clone ( ) ,
621
+ metadata : status. 0 . metadata . clone ( ) ,
622
+ // Since `Status` is not `Clone`, any `source` on the original Status
623
+ // cannot be cloned so must remain with the original `Status`.
624
+ source : None ,
625
+ }
626
+ . into ( ) ,
627
+ ) ;
610
628
}
611
629
612
630
if let Some ( timeout) = err. downcast_ref :: < TimeoutExpired > ( ) {
@@ -637,6 +655,12 @@ fn find_status_in_source_chain(err: &(dyn Error + 'static)) -> Option<Status> {
637
655
}
638
656
639
657
impl fmt:: Debug for Status {
658
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
659
+ self . 0 . fmt ( f)
660
+ }
661
+ }
662
+
663
+ impl fmt:: Debug for StatusInner {
640
664
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
641
665
// A manual impl to reduce the noise of frequently empty fields.
642
666
let mut builder = f. debug_struct ( "Status" ) ;
@@ -725,7 +749,7 @@ impl fmt::Display for Status {
725
749
726
750
impl Error for Status {
727
751
fn source ( & self ) -> Option < & ( dyn Error + ' static ) > {
728
- self . source . as_ref ( ) . map ( |err| ( & * * err) as _ )
752
+ self . 0 . source . as_ref ( ) . map ( |err| ( & * * err) as _ )
729
753
}
730
754
}
731
755
0 commit comments