Skip to content

Commit 5de7bad

Browse files
authored
chore: box Status contents (#2253) (#2282)
* chore: box Status contents (#2253) * chore: use private into_status method
1 parent 2bd66e4 commit 5de7bad

File tree

1 file changed

+60
-36
lines changed

1 file changed

+60
-36
lines changed

tonic/src/status.rs

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ const ENCODING_SET: &AsciiSet = &CONTROLS
3535
/// assert_eq!(status1.code(), status2.code());
3636
/// ```
3737
#[derive(Clone)]
38-
pub struct Status {
38+
pub struct Status(Box<StatusInner>);
39+
40+
/// Box the contents of Status to avoid large error variants
41+
#[derive(Clone)]
42+
struct StatusInner {
3943
/// The gRPC status code, found in the `grpc-status` header.
4044
code: Code,
4145
/// A relevant error message, found in the `grpc-message` header.
@@ -50,6 +54,12 @@ pub struct Status {
5054
source: Option<Arc<dyn Error + Send + Sync + 'static>>,
5155
}
5256

57+
impl StatusInner {
58+
fn into_status(self) -> Status {
59+
Status(Box::new(self))
60+
}
61+
}
62+
5363
/// gRPC status codes used by [`Status`].
5464
///
5565
/// These variants match the [gRPC status codes].
@@ -160,13 +170,14 @@ impl std::fmt::Display for Code {
160170
impl Status {
161171
/// Create a new `Status` with the associated code and message.
162172
pub fn new(code: Code, message: impl Into<String>) -> Status {
163-
Status {
173+
StatusInner {
164174
code,
165175
message: message.into(),
166176
details: Bytes::new(),
167177
metadata: MetadataMap::new(),
168178
source: None,
169179
}
180+
.into_status()
170181
}
171182

172183
/// The operation completed successfully.
@@ -318,7 +329,7 @@ impl Status {
318329
pub fn from_error(err: Box<dyn Error + Send + Sync + 'static>) -> Status {
319330
Status::try_from_error(err).unwrap_or_else(|err| {
320331
let mut status = Status::new(Code::Unknown, err.to_string());
321-
status.source = Some(err.into());
332+
status.0.source = Some(err.into());
322333
status
323334
})
324335
}
@@ -361,7 +372,7 @@ impl Status {
361372
};
362373

363374
if let Some(mut status) = find_status_in_source_chain(&*err) {
364-
status.source = Some(err.into());
375+
status.0.source = Some(err.into());
365376
return Ok(status);
366377
}
367378

@@ -374,7 +385,7 @@ impl Status {
374385
let code = Self::code_from_h2(&err);
375386

376387
let mut status = Self::new(code, format!("h2 protocol error: {err}"));
377-
status.source = Some(Arc::new(*err));
388+
status.0.source = Some(Arc::new(*err));
378389
status
379390
}
380391

@@ -401,7 +412,7 @@ impl Status {
401412
#[cfg(feature = "server")]
402413
fn to_h2_error(&self) -> h2::Error {
403414
// conservatively transform to h2 error codes...
404-
let reason = match self.code {
415+
let reason = match self.code() {
405416
Code::Cancelled => h2::Reason::CANCEL,
406417
_ => h2::Reason::INTERNAL_ERROR,
407418
};
@@ -485,53 +496,56 @@ impl Status {
485496
}
486497
};
487498

488-
Some(Status {
489-
code,
490-
message,
491-
details,
492-
metadata: MetadataMap::from_headers(other_headers),
493-
source: None,
494-
})
499+
Some(
500+
StatusInner {
501+
code,
502+
message,
503+
details,
504+
metadata: MetadataMap::from_headers(other_headers),
505+
source: None,
506+
}
507+
.into_status(),
508+
)
495509
}
496510

497511
/// Get the gRPC `Code` of this `Status`.
498512
pub fn code(&self) -> Code {
499-
self.code
513+
self.0.code
500514
}
501515

502516
/// Get the text error message of this `Status`.
503517
pub fn message(&self) -> &str {
504-
&self.message
518+
&self.0.message
505519
}
506520

507521
/// Get the opaque error details of this `Status`.
508522
pub fn details(&self) -> &[u8] {
509-
&self.details
523+
&self.0.details
510524
}
511525

512526
/// Get a reference to the custom metadata.
513527
pub fn metadata(&self) -> &MetadataMap {
514-
&self.metadata
528+
&self.0.metadata
515529
}
516530

517531
/// Get a mutable reference to the custom metadata.
518532
pub fn metadata_mut(&mut self) -> &mut MetadataMap {
519-
&mut self.metadata
533+
&mut self.0.metadata
520534
}
521535

522536
pub(crate) fn to_header_map(&self) -> Result<HeaderMap, Self> {
523-
let mut header_map = HeaderMap::with_capacity(3 + self.metadata.len());
537+
let mut header_map = HeaderMap::with_capacity(3 + self.0.metadata.len());
524538
self.add_header(&mut header_map)?;
525539
Ok(header_map)
526540
}
527541

528542
/// Add headers from this `Status` into `header_map`.
529543
pub fn add_header(&self, header_map: &mut HeaderMap) -> Result<(), Self> {
530-
header_map.extend(self.metadata.clone().into_sanitized_headers());
544+
header_map.extend(self.0.metadata.clone().into_sanitized_headers());
531545

532-
header_map.insert(Self::GRPC_STATUS, self.code.to_header_value());
546+
header_map.insert(Self::GRPC_STATUS, self.0.code.to_header_value());
533547

534-
if !self.message.is_empty() {
548+
if !self.0.message.is_empty() {
535549
let to_write = Bytes::copy_from_slice(
536550
Cow::from(percent_encode(self.message().as_bytes(), ENCODING_SET)).as_bytes(),
537551
);
@@ -542,8 +556,8 @@ impl Status {
542556
);
543557
}
544558

545-
if !self.details.is_empty() {
546-
let details = crate::util::base64::STANDARD_NO_PAD.encode(&self.details[..]);
559+
if !self.0.details.is_empty() {
560+
let details = crate::util::base64::STANDARD_NO_PAD.encode(&self.0.details[..]);
547561

548562
header_map.insert(
549563
Self::GRPC_STATUS_DETAILS,
@@ -571,18 +585,19 @@ impl Status {
571585
details: Bytes,
572586
metadata: MetadataMap,
573587
) -> Status {
574-
Status {
588+
StatusInner {
575589
code,
576590
message: message.into(),
577591
details,
578592
metadata,
579593
source: None,
580594
}
595+
.into_status()
581596
}
582597

583598
/// Add a source error to this status.
584599
pub fn set_source(&mut self, source: Arc<dyn Error + Send + Sync + 'static>) -> &mut Status {
585-
self.source = Some(source);
600+
self.0.source = Some(source);
586601
self
587602
}
588603

@@ -610,15 +625,18 @@ fn find_status_in_source_chain(err: &(dyn Error + 'static)) -> Option<Status> {
610625

611626
while let Some(err) = source {
612627
if let Some(status) = err.downcast_ref::<Status>() {
613-
return Some(Status {
614-
code: status.code,
615-
message: status.message.clone(),
616-
details: status.details.clone(),
617-
metadata: status.metadata.clone(),
618-
// Since `Status` is not `Clone`, any `source` on the original Status
619-
// cannot be cloned so must remain with the original `Status`.
620-
source: None,
621-
});
628+
return Some(
629+
StatusInner {
630+
code: status.0.code,
631+
message: status.0.message.clone(),
632+
details: status.0.details.clone(),
633+
metadata: status.0.metadata.clone(),
634+
// Since `Status` is not `Clone`, any `source` on the original Status
635+
// cannot be cloned so must remain with the original `Status`.
636+
source: None,
637+
}
638+
.into_status(),
639+
);
622640
}
623641

624642
if let Some(timeout) = err.downcast_ref::<TimeoutExpired>() {
@@ -649,6 +667,12 @@ fn find_status_in_source_chain(err: &(dyn Error + 'static)) -> Option<Status> {
649667
}
650668

651669
impl fmt::Debug for Status {
670+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
671+
self.0.fmt(f)
672+
}
673+
}
674+
675+
impl fmt::Debug for StatusInner {
652676
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
653677
// A manual impl to reduce the noise of frequently empty fields.
654678
let mut builder = f.debug_struct("Status");
@@ -737,7 +761,7 @@ impl fmt::Display for Status {
737761

738762
impl Error for Status {
739763
fn source(&self) -> Option<&(dyn Error + 'static)> {
740-
self.source.as_ref().map(|err| (&**err) as _)
764+
self.0.source.as_ref().map(|err| (&**err) as _)
741765
}
742766
}
743767

0 commit comments

Comments
 (0)