1 use std::{collections::HashMap, time};
2 
3 use super::std_messages::{
4     BadRequest, DebugInfo, ErrorInfo, FieldViolation, Help, HelpLink, LocalizedMessage,
5     PreconditionFailure, PreconditionViolation, QuotaFailure, QuotaViolation, RequestInfo,
6     ResourceInfo, RetryInfo,
7 };
8 
9 pub(crate) mod vec;
10 
11 /// Groups the standard error messages structs. Provides associated
12 /// functions and methods to setup and edit each error message independently.
13 /// Used when extracting error details from `tonic::Status`, and when
14 /// creating a `tonic::Status` with error details.
15 #[non_exhaustive]
16 #[derive(Clone, Debug, Default)]
17 pub struct ErrorDetails {
18     /// This field stores [`RetryInfo`] data, if any.
19     pub(crate) retry_info: Option<RetryInfo>,
20 
21     /// This field stores [`DebugInfo`] data, if any.
22     pub(crate) debug_info: Option<DebugInfo>,
23 
24     /// This field stores [`QuotaFailure`] data, if any.
25     pub(crate) quota_failure: Option<QuotaFailure>,
26 
27     /// This field stores [`ErrorInfo`] data, if any.
28     pub(crate) error_info: Option<ErrorInfo>,
29 
30     /// This field stores [`PreconditionFailure`] data, if any.
31     pub(crate) precondition_failure: Option<PreconditionFailure>,
32 
33     /// This field stores [`BadRequest`] data, if any.
34     pub(crate) bad_request: Option<BadRequest>,
35 
36     /// This field stores [`RequestInfo`] data, if any.
37     pub(crate) request_info: Option<RequestInfo>,
38 
39     /// This field stores [`ResourceInfo`] data, if any.
40     pub(crate) resource_info: Option<ResourceInfo>,
41 
42     /// This field stores [`Help`] data, if any.
43     pub(crate) help: Option<Help>,
44 
45     /// This field stores [`LocalizedMessage`] data, if any.
46     pub(crate) localized_message: Option<LocalizedMessage>,
47 }
48 
49 impl ErrorDetails {
50     /// Generates an [`ErrorDetails`] struct with all fields set to `None`.
51     ///
52     /// # Examples
53     ///
54     /// ```
55     /// use tonic_types::ErrorDetails;
56     ///
57     /// let err_details = ErrorDetails::new();
58     /// ```
new() -> Self59     pub fn new() -> Self {
60         Self::default()
61     }
62 
63     /// Generates an [`ErrorDetails`] struct with [`RetryInfo`] details and
64     /// remaining fields set to `None`.
65     ///
66     /// # Examples
67     ///
68     /// ```
69     /// use std::time::Duration;
70     /// use tonic_types::ErrorDetails;
71     ///
72     /// let err_details = ErrorDetails::with_retry_info(Some(Duration::from_secs(5)));
73     /// ```
with_retry_info(retry_delay: Option<time::Duration>) -> Self74     pub fn with_retry_info(retry_delay: Option<time::Duration>) -> Self {
75         ErrorDetails {
76             retry_info: Some(RetryInfo::new(retry_delay)),
77             ..ErrorDetails::new()
78         }
79     }
80 
81     /// Generates an [`ErrorDetails`] struct with [`DebugInfo`] details and
82     /// remaining fields set to `None`.
83     ///
84     /// # Examples
85     ///
86     /// ```
87     /// use tonic_types::ErrorDetails;
88     ///
89     /// let err_stack = vec!["...".into(), "...".into()];
90     ///
91     /// let err_details = ErrorDetails::with_debug_info(err_stack, "error details");
92     /// ```
with_debug_info( stack_entries: impl Into<Vec<String>>, detail: impl Into<String>, ) -> Self93     pub fn with_debug_info(
94         stack_entries: impl Into<Vec<String>>,
95         detail: impl Into<String>,
96     ) -> Self {
97         ErrorDetails {
98             debug_info: Some(DebugInfo::new(stack_entries, detail)),
99             ..ErrorDetails::new()
100         }
101     }
102 
103     /// Generates an [`ErrorDetails`] struct with [`QuotaFailure`] details and
104     /// remaining fields set to `None`.
105     ///
106     /// # Examples
107     ///
108     /// ```
109     /// use tonic_types::{ErrorDetails, QuotaViolation};
110     ///
111     /// let err_details = ErrorDetails::with_quota_failure(vec![
112     ///     QuotaViolation::new("subject 1", "description 1"),
113     ///     QuotaViolation::new("subject 2", "description 2"),
114     /// ]);
115     /// ```
with_quota_failure(violations: impl Into<Vec<QuotaViolation>>) -> Self116     pub fn with_quota_failure(violations: impl Into<Vec<QuotaViolation>>) -> Self {
117         ErrorDetails {
118             quota_failure: Some(QuotaFailure::new(violations)),
119             ..ErrorDetails::new()
120         }
121     }
122 
123     /// Generates an [`ErrorDetails`] struct with [`QuotaFailure`] details (one
124     /// [`QuotaViolation`] set) and remaining fields set to `None`.
125     ///
126     /// # Examples
127     ///
128     /// ```
129     /// use tonic_types::ErrorDetails;
130     ///
131     /// let err_details = ErrorDetails::with_quota_failure_violation("subject", "description");
132     /// ```
with_quota_failure_violation( subject: impl Into<String>, description: impl Into<String>, ) -> Self133     pub fn with_quota_failure_violation(
134         subject: impl Into<String>,
135         description: impl Into<String>,
136     ) -> Self {
137         ErrorDetails {
138             quota_failure: Some(QuotaFailure::with_violation(subject, description)),
139             ..ErrorDetails::new()
140         }
141     }
142 
143     /// Generates an [`ErrorDetails`] struct with [`ErrorInfo`] details and
144     /// remaining fields set to `None`.
145     ///
146     /// # Examples
147     ///
148     /// ```
149     /// use std::collections::HashMap;
150     /// use tonic_types::ErrorDetails;
151     ///
152     /// let mut metadata: HashMap<String, String> = HashMap::new();
153     /// metadata.insert("instanceLimitPerRequest".into(), "100".into());
154     ///
155     /// let err_details = ErrorDetails::with_error_info("reason", "domain", metadata);
156     /// ```
with_error_info( reason: impl Into<String>, domain: impl Into<String>, metadata: impl Into<HashMap<String, String>>, ) -> Self157     pub fn with_error_info(
158         reason: impl Into<String>,
159         domain: impl Into<String>,
160         metadata: impl Into<HashMap<String, String>>,
161     ) -> Self {
162         ErrorDetails {
163             error_info: Some(ErrorInfo::new(reason, domain, metadata)),
164             ..ErrorDetails::new()
165         }
166     }
167 
168     /// Generates an [`ErrorDetails`] struct with [`PreconditionFailure`]
169     /// details and remaining fields set to `None`.
170     ///
171     /// # Examples
172     ///
173     /// ```
174     /// use tonic_types::{ErrorDetails, PreconditionViolation};
175     ///
176     /// let err_details = ErrorDetails::with_precondition_failure(vec![
177     ///     PreconditionViolation::new(
178     ///         "violation type 1",
179     ///         "subject 1",
180     ///         "description 1",
181     ///     ),
182     ///     PreconditionViolation::new(
183     ///         "violation type 2",
184     ///         "subject 2",
185     ///         "description 2",
186     ///     ),
187     /// ]);
188     /// ```
with_precondition_failure(violations: impl Into<Vec<PreconditionViolation>>) -> Self189     pub fn with_precondition_failure(violations: impl Into<Vec<PreconditionViolation>>) -> Self {
190         ErrorDetails {
191             precondition_failure: Some(PreconditionFailure::new(violations)),
192             ..ErrorDetails::new()
193         }
194     }
195 
196     /// Generates an [`ErrorDetails`] struct with [`PreconditionFailure`]
197     /// details (one [`PreconditionViolation`] set) and remaining fields set to
198     /// `None`.
199     ///
200     /// # Examples
201     ///
202     /// ```
203     /// use tonic_types::ErrorDetails;
204     ///
205     /// let err_details = ErrorDetails::with_precondition_failure_violation(
206     ///     "violation type",
207     ///     "subject",
208     ///     "description",
209     /// );
210     /// ```
with_precondition_failure_violation( violation_type: impl Into<String>, subject: impl Into<String>, description: impl Into<String>, ) -> Self211     pub fn with_precondition_failure_violation(
212         violation_type: impl Into<String>,
213         subject: impl Into<String>,
214         description: impl Into<String>,
215     ) -> Self {
216         ErrorDetails {
217             precondition_failure: Some(PreconditionFailure::with_violation(
218                 violation_type,
219                 subject,
220                 description,
221             )),
222             ..ErrorDetails::new()
223         }
224     }
225 
226     /// Generates an [`ErrorDetails`] struct with [`BadRequest`] details and
227     /// remaining fields set to `None`.
228     ///
229     /// # Examples
230     ///
231     /// ```
232     /// use tonic_types::{ErrorDetails, FieldViolation};
233     ///
234     /// let err_details = ErrorDetails::with_bad_request(vec![
235     ///     FieldViolation::new("field_1", "description 1"),
236     ///     FieldViolation::new("field_2", "description 2"),
237     /// ]);
238     /// ```
with_bad_request(field_violations: impl Into<Vec<FieldViolation>>) -> Self239     pub fn with_bad_request(field_violations: impl Into<Vec<FieldViolation>>) -> Self {
240         ErrorDetails {
241             bad_request: Some(BadRequest::new(field_violations)),
242             ..ErrorDetails::new()
243         }
244     }
245 
246     /// Generates an [`ErrorDetails`] struct with [`BadRequest`] details (one
247     /// [`FieldViolation`] set) and remaining fields set to `None`.
248     ///
249     /// # Examples
250     ///
251     /// ```
252     /// use tonic_types::ErrorDetails;
253     ///
254     /// let err_details = ErrorDetails::with_bad_request_violation(
255     ///     "field",
256     ///     "description",
257     /// );
258     /// ```
with_bad_request_violation( field: impl Into<String>, description: impl Into<String>, ) -> Self259     pub fn with_bad_request_violation(
260         field: impl Into<String>,
261         description: impl Into<String>,
262     ) -> Self {
263         ErrorDetails {
264             bad_request: Some(BadRequest::with_violation(field, description)),
265             ..ErrorDetails::new()
266         }
267     }
268 
269     /// Generates an [`ErrorDetails`] struct with [`RequestInfo`] details and
270     /// remaining fields set to `None`.
271     ///
272     /// # Examples
273     ///
274     /// ```
275     /// use tonic_types::ErrorDetails;
276     ///
277     /// let err_details = ErrorDetails::with_request_info(
278     ///     "request_id",
279     ///     "serving_data",
280     /// );
281     /// ```
with_request_info( request_id: impl Into<String>, serving_data: impl Into<String>, ) -> Self282     pub fn with_request_info(
283         request_id: impl Into<String>,
284         serving_data: impl Into<String>,
285     ) -> Self {
286         ErrorDetails {
287             request_info: Some(RequestInfo::new(request_id, serving_data)),
288             ..ErrorDetails::new()
289         }
290     }
291 
292     /// Generates an [`ErrorDetails`] struct with [`ResourceInfo`] details and
293     /// remaining fields set to `None`.
294     ///
295     /// # Examples
296     ///
297     /// ```
298     /// use tonic_types::ErrorDetails;
299     ///
300     /// let err_details = ErrorDetails::with_resource_info(
301     ///     "res_type",
302     ///     "res_name",
303     ///     "owner",
304     ///     "description",
305     /// );
306     /// ```
with_resource_info( resource_type: impl Into<String>, resource_name: impl Into<String>, owner: impl Into<String>, description: impl Into<String>, ) -> Self307     pub fn with_resource_info(
308         resource_type: impl Into<String>,
309         resource_name: impl Into<String>,
310         owner: impl Into<String>,
311         description: impl Into<String>,
312     ) -> Self {
313         ErrorDetails {
314             resource_info: Some(ResourceInfo::new(
315                 resource_type,
316                 resource_name,
317                 owner,
318                 description,
319             )),
320             ..ErrorDetails::new()
321         }
322     }
323 
324     /// Generates an [`ErrorDetails`] struct with [`Help`] details and
325     /// remaining fields set to `None`.
326     ///
327     /// # Examples
328     ///
329     /// ```
330     /// use tonic_types::{ErrorDetails, HelpLink};
331     ///
332     /// let err_details = ErrorDetails::with_help(vec![
333     ///     HelpLink::new("description of link a", "resource-a.example.local"),
334     ///     HelpLink::new("description of link b", "resource-b.example.local"),
335     /// ]);
336     /// ```
with_help(links: impl Into<Vec<HelpLink>>) -> Self337     pub fn with_help(links: impl Into<Vec<HelpLink>>) -> Self {
338         ErrorDetails {
339             help: Some(Help::new(links)),
340             ..ErrorDetails::new()
341         }
342     }
343 
344     /// Generates an [`ErrorDetails`] struct with [`Help`] details (one
345     /// [`HelpLink`] set) and remaining fields set to `None`.
346     ///
347     /// # Examples
348     ///
349     /// ```
350     /// use tonic_types::ErrorDetails;
351     ///
352     /// let err_details = ErrorDetails::with_help_link(
353     ///     "description of link a",
354     ///     "resource-a.example.local"
355     /// );
356     /// ```
with_help_link(description: impl Into<String>, url: impl Into<String>) -> Self357     pub fn with_help_link(description: impl Into<String>, url: impl Into<String>) -> Self {
358         ErrorDetails {
359             help: Some(Help::with_link(description, url)),
360             ..ErrorDetails::new()
361         }
362     }
363 
364     /// Generates an [`ErrorDetails`] struct with [`LocalizedMessage`] details
365     /// and remaining fields set to `None`.
366     ///
367     /// # Examples
368     ///
369     /// ```
370     /// use tonic_types::ErrorDetails;
371     ///
372     /// let err_details = ErrorDetails::with_localized_message(
373     ///     "en-US",
374     ///     "message for the user"
375     /// );
376     /// ```
with_localized_message(locale: impl Into<String>, message: impl Into<String>) -> Self377     pub fn with_localized_message(locale: impl Into<String>, message: impl Into<String>) -> Self {
378         ErrorDetails {
379             localized_message: Some(LocalizedMessage::new(locale, message)),
380             ..ErrorDetails::new()
381         }
382     }
383 
384     /// Get [`RetryInfo`] details, if any.
retry_info(&self) -> Option<&RetryInfo>385     pub fn retry_info(&self) -> Option<&RetryInfo> {
386         self.retry_info.as_ref()
387     }
388 
389     /// Get [`DebugInfo`] details, if any.
debug_info(&self) -> Option<&DebugInfo>390     pub fn debug_info(&self) -> Option<&DebugInfo> {
391         self.debug_info.as_ref()
392     }
393 
394     /// Get [`QuotaFailure`] details, if any.
quota_failure(&self) -> Option<&QuotaFailure>395     pub fn quota_failure(&self) -> Option<&QuotaFailure> {
396         self.quota_failure.as_ref()
397     }
398 
399     /// Get [`ErrorInfo`] details, if any.
error_info(&self) -> Option<&ErrorInfo>400     pub fn error_info(&self) -> Option<&ErrorInfo> {
401         self.error_info.as_ref()
402     }
403 
404     /// Get [`PreconditionFailure`] details, if any.
precondition_failure(&self) -> Option<&PreconditionFailure>405     pub fn precondition_failure(&self) -> Option<&PreconditionFailure> {
406         self.precondition_failure.as_ref()
407     }
408 
409     /// Get [`BadRequest`] details, if any.
bad_request(&self) -> Option<&BadRequest>410     pub fn bad_request(&self) -> Option<&BadRequest> {
411         self.bad_request.as_ref()
412     }
413 
414     /// Get [`RequestInfo`] details, if any.
request_info(&self) -> Option<&RequestInfo>415     pub fn request_info(&self) -> Option<&RequestInfo> {
416         self.request_info.as_ref()
417     }
418 
419     /// Get [`ResourceInfo`] details, if any.
resource_info(&self) -> Option<&ResourceInfo>420     pub fn resource_info(&self) -> Option<&ResourceInfo> {
421         self.resource_info.as_ref()
422     }
423 
424     /// Get [`Help`] details, if any.
help(&self) -> Option<&Help>425     pub fn help(&self) -> Option<&Help> {
426         self.help.as_ref()
427     }
428 
429     /// Get [`LocalizedMessage`] details, if any.
localized_message(&self) -> Option<&LocalizedMessage>430     pub fn localized_message(&self) -> Option<&LocalizedMessage> {
431         self.localized_message.as_ref()
432     }
433 
434     /// Set [`RetryInfo`] details. Can be chained with other `.set_` and
435     /// `.add_` [`ErrorDetails`] methods.
436     ///
437     /// # Examples
438     ///
439     /// ```
440     /// use std::time::Duration;
441     /// use tonic_types::ErrorDetails;
442     ///
443     /// let mut err_details = ErrorDetails::new();
444     ///
445     /// err_details.set_retry_info(Some(Duration::from_secs(5)));
446     /// ```
set_retry_info(&mut self, retry_delay: Option<time::Duration>) -> &mut Self447     pub fn set_retry_info(&mut self, retry_delay: Option<time::Duration>) -> &mut Self {
448         self.retry_info = Some(RetryInfo::new(retry_delay));
449         self
450     }
451 
452     /// Set [`DebugInfo`] details. Can be chained with other `.set_` and
453     /// `.add_` [`ErrorDetails`] methods.
454     ///
455     /// # Examples
456     ///
457     /// ```
458     /// use tonic_types::ErrorDetails;
459     ///
460     /// let mut err_details = ErrorDetails::new();
461     ///
462     /// let err_stack = vec!["...".into(), "...".into()];
463     ///
464     /// err_details.set_debug_info(err_stack, "error details");
465     /// ```
set_debug_info( &mut self, stack_entries: impl Into<Vec<String>>, detail: impl Into<String>, ) -> &mut Self466     pub fn set_debug_info(
467         &mut self,
468         stack_entries: impl Into<Vec<String>>,
469         detail: impl Into<String>,
470     ) -> &mut Self {
471         self.debug_info = Some(DebugInfo::new(stack_entries, detail));
472         self
473     }
474 
475     /// Set [`QuotaFailure`] details. Can be chained with other `.set_` and
476     /// `.add_` [`ErrorDetails`] methods.
477     ///
478     /// # Examples
479     ///
480     /// ```
481     /// use tonic_types::{ErrorDetails, QuotaViolation};
482     ///
483     /// let mut err_details = ErrorDetails::new();
484     ///
485     /// err_details.set_quota_failure(vec![
486     ///     QuotaViolation::new("subject 1", "description 1"),
487     ///     QuotaViolation::new("subject 2", "description 2"),
488     /// ]);
489     /// ```
set_quota_failure(&mut self, violations: impl Into<Vec<QuotaViolation>>) -> &mut Self490     pub fn set_quota_failure(&mut self, violations: impl Into<Vec<QuotaViolation>>) -> &mut Self {
491         self.quota_failure = Some(QuotaFailure::new(violations));
492         self
493     }
494 
495     /// Adds a [`QuotaViolation`] to [`QuotaFailure`] details. Sets
496     /// [`QuotaFailure`] details if it is not set yet. Can be chained with
497     /// other `.set_` and `.add_` [`ErrorDetails`] methods.
498     ///
499     /// # Examples
500     ///
501     /// ```
502     /// use tonic_types::ErrorDetails;
503     ///
504     /// let mut err_details = ErrorDetails::new();
505     ///
506     /// err_details.add_quota_failure_violation("subject", "description");
507     /// ```
add_quota_failure_violation( &mut self, subject: impl Into<String>, description: impl Into<String>, ) -> &mut Self508     pub fn add_quota_failure_violation(
509         &mut self,
510         subject: impl Into<String>,
511         description: impl Into<String>,
512     ) -> &mut Self {
513         match &mut self.quota_failure {
514             Some(quota_failure) => {
515                 quota_failure.add_violation(subject, description);
516             }
517             None => {
518                 self.quota_failure = Some(QuotaFailure::with_violation(subject, description));
519             }
520         };
521         self
522     }
523 
524     /// Returns `true` if [`QuotaFailure`] is set and its `violations` vector
525     /// is not empty, otherwise returns `false`.
526     ///
527     /// # Examples
528     ///
529     /// ```
530     /// use tonic_types::ErrorDetails;
531     ///
532     /// let mut err_details = ErrorDetails::with_quota_failure(vec![]);
533     ///
534     /// assert_eq!(err_details.has_quota_failure_violations(), false);
535     ///
536     /// err_details.add_quota_failure_violation("subject", "description");
537     ///
538     /// assert_eq!(err_details.has_quota_failure_violations(), true);
539     /// ```
has_quota_failure_violations(&self) -> bool540     pub fn has_quota_failure_violations(&self) -> bool {
541         if let Some(quota_failure) = &self.quota_failure {
542             return !quota_failure.violations.is_empty();
543         }
544         false
545     }
546 
547     /// Set [`ErrorInfo`] details. Can be chained with other `.set_` and
548     /// `.add_` [`ErrorDetails`] methods.
549     ///
550     /// # Examples
551     ///
552     /// ```
553     /// use std::collections::HashMap;
554     /// use tonic_types::ErrorDetails;
555     ///
556     /// let mut err_details = ErrorDetails::new();
557     ///
558     /// let mut metadata: HashMap<String, String> = HashMap::new();
559     /// metadata.insert("instanceLimitPerRequest".into(), "100".into());
560     ///
561     /// err_details.set_error_info("reason", "example.local", metadata);
562     /// ```
set_error_info( &mut self, reason: impl Into<String>, domain: impl Into<String>, metadata: impl Into<HashMap<String, String>>, ) -> &mut Self563     pub fn set_error_info(
564         &mut self,
565         reason: impl Into<String>,
566         domain: impl Into<String>,
567         metadata: impl Into<HashMap<String, String>>,
568     ) -> &mut Self {
569         self.error_info = Some(ErrorInfo::new(reason, domain, metadata));
570         self
571     }
572 
573     /// Set [`PreconditionFailure`] details. Can be chained with other `.set_`
574     /// and `.add_` [`ErrorDetails`] methods.
575     ///
576     /// # Examples
577     ///
578     /// ```
579     /// use tonic_types::{ErrorDetails, PreconditionViolation};
580     ///
581     /// let mut err_details = ErrorDetails::new();
582     ///
583     /// err_details.set_precondition_failure(vec![
584     ///     PreconditionViolation::new(
585     ///         "violation type 1",
586     ///         "subject 1",
587     ///         "description 1",
588     ///     ),
589     ///     PreconditionViolation::new(
590     ///         "violation type 2",
591     ///         "subject 2",
592     ///         "description 2",
593     ///     ),
594     /// ]);
595     /// ```
set_precondition_failure( &mut self, violations: impl Into<Vec<PreconditionViolation>>, ) -> &mut Self596     pub fn set_precondition_failure(
597         &mut self,
598         violations: impl Into<Vec<PreconditionViolation>>,
599     ) -> &mut Self {
600         self.precondition_failure = Some(PreconditionFailure::new(violations));
601         self
602     }
603 
604     /// Adds a [`PreconditionViolation`] to [`PreconditionFailure`] details.
605     /// Sets [`PreconditionFailure`] details if it is not set yet. Can be
606     /// chained with other `.set_` and `.add_` [`ErrorDetails`] methods.
607     ///
608     /// # Examples
609     ///
610     /// ```
611     /// use tonic_types::ErrorDetails;
612     ///
613     /// let mut err_details = ErrorDetails::new();
614     ///
615     /// err_details.add_precondition_failure_violation(
616     ///     "violation type",
617     ///     "subject",
618     ///     "description"
619     /// );
620     /// ```
add_precondition_failure_violation( &mut self, violation_type: impl Into<String>, subject: impl Into<String>, description: impl Into<String>, ) -> &mut Self621     pub fn add_precondition_failure_violation(
622         &mut self,
623         violation_type: impl Into<String>,
624         subject: impl Into<String>,
625         description: impl Into<String>,
626     ) -> &mut Self {
627         match &mut self.precondition_failure {
628             Some(precondition_failure) => {
629                 precondition_failure.add_violation(violation_type, subject, description);
630             }
631             None => {
632                 self.precondition_failure = Some(PreconditionFailure::with_violation(
633                     violation_type,
634                     subject,
635                     description,
636                 ));
637             }
638         };
639         self
640     }
641 
642     /// Returns `true` if [`PreconditionFailure`] is set and its `violations`
643     /// vector is not empty, otherwise returns `false`.
644     ///
645     /// # Examples
646     ///
647     /// ```
648     /// use tonic_types::ErrorDetails;
649     ///
650     /// let mut err_details = ErrorDetails::with_precondition_failure(vec![]);
651     ///
652     /// assert_eq!(err_details.has_precondition_failure_violations(), false);
653     ///
654     /// err_details.add_precondition_failure_violation(
655     ///     "violation type",
656     ///     "subject",
657     ///     "description"
658     /// );
659     ///
660     /// assert_eq!(err_details.has_precondition_failure_violations(), true);
661     /// ```
has_precondition_failure_violations(&self) -> bool662     pub fn has_precondition_failure_violations(&self) -> bool {
663         if let Some(precondition_failure) = &self.precondition_failure {
664             return !precondition_failure.violations.is_empty();
665         }
666         false
667     }
668 
669     /// Set [`BadRequest`] details. Can be chained with other `.set_` and
670     /// `.add_` [`ErrorDetails`] methods.
671     ///
672     /// # Examples
673     ///
674     /// ```
675     /// use tonic_types::{ErrorDetails, FieldViolation};
676     ///
677     /// let mut err_details = ErrorDetails::new();
678     ///
679     /// err_details.set_bad_request(vec![
680     ///     FieldViolation::new("field_1", "description 1"),
681     ///     FieldViolation::new("field_2", "description 2"),
682     /// ]);
683     /// ```
set_bad_request(&mut self, violations: impl Into<Vec<FieldViolation>>) -> &mut Self684     pub fn set_bad_request(&mut self, violations: impl Into<Vec<FieldViolation>>) -> &mut Self {
685         self.bad_request = Some(BadRequest::new(violations));
686         self
687     }
688 
689     /// Adds a [`FieldViolation`] to [`BadRequest`] details. Sets
690     /// [`BadRequest`] details if it is not set yet. Can be chained with other
691     /// `.set_` and `.add_` [`ErrorDetails`] methods.
692     ///
693     /// # Examples
694     ///
695     /// ```
696     /// use tonic_types::ErrorDetails;
697     ///
698     /// let mut err_details = ErrorDetails::new();
699     ///
700     /// err_details.add_bad_request_violation("field", "description");
701     /// ```
add_bad_request_violation( &mut self, field: impl Into<String>, description: impl Into<String>, ) -> &mut Self702     pub fn add_bad_request_violation(
703         &mut self,
704         field: impl Into<String>,
705         description: impl Into<String>,
706     ) -> &mut Self {
707         match &mut self.bad_request {
708             Some(bad_request) => {
709                 bad_request.add_violation(field, description);
710             }
711             None => {
712                 self.bad_request = Some(BadRequest::with_violation(field, description));
713             }
714         };
715         self
716     }
717 
718     /// Returns `true` if [`BadRequest`] is set and its `field_violations`
719     /// vector is not empty, otherwise returns `false`.
720     ///
721     /// # Examples
722     ///
723     /// ```
724     /// use tonic_types::ErrorDetails;
725     ///
726     /// let mut err_details = ErrorDetails::with_bad_request(vec![]);
727     ///
728     /// assert_eq!(err_details.has_bad_request_violations(), false);
729     ///
730     /// err_details.add_bad_request_violation("field", "description");
731     ///
732     /// assert_eq!(err_details.has_bad_request_violations(), true);
733     /// ```
has_bad_request_violations(&self) -> bool734     pub fn has_bad_request_violations(&self) -> bool {
735         if let Some(bad_request) = &self.bad_request {
736             return !bad_request.field_violations.is_empty();
737         }
738         false
739     }
740 
741     /// Set [`RequestInfo`] details. Can be chained with other `.set_` and
742     /// `.add_` [`ErrorDetails`] methods.
743     ///
744     /// # Examples
745     ///
746     /// ```
747     /// use tonic_types::ErrorDetails;
748     ///
749     /// let mut err_details = ErrorDetails::new();
750     ///
751     /// err_details.set_request_info("request_id", "serving_data");
752     /// ```
set_request_info( &mut self, request_id: impl Into<String>, serving_data: impl Into<String>, ) -> &mut Self753     pub fn set_request_info(
754         &mut self,
755         request_id: impl Into<String>,
756         serving_data: impl Into<String>,
757     ) -> &mut Self {
758         self.request_info = Some(RequestInfo::new(request_id, serving_data));
759         self
760     }
761 
762     /// Set [`ResourceInfo`] details. Can be chained with other `.set_` and
763     /// `.add_` [`ErrorDetails`] methods.
764     ///
765     /// # Examples
766     ///
767     /// ```
768     /// use tonic_types::ErrorDetails;
769     ///
770     /// let mut err_details = ErrorDetails::new();
771     ///
772     /// err_details.set_resource_info("res_type", "res_name", "owner", "description");
773     /// ```
set_resource_info( &mut self, resource_type: impl Into<String>, resource_name: impl Into<String>, owner: impl Into<String>, description: impl Into<String>, ) -> &mut Self774     pub fn set_resource_info(
775         &mut self,
776         resource_type: impl Into<String>,
777         resource_name: impl Into<String>,
778         owner: impl Into<String>,
779         description: impl Into<String>,
780     ) -> &mut Self {
781         self.resource_info = Some(ResourceInfo::new(
782             resource_type,
783             resource_name,
784             owner,
785             description,
786         ));
787         self
788     }
789 
790     /// Set [`Help`] details. Can be chained with other `.set_` and `.add_`
791     /// [`ErrorDetails`] methods.
792     ///
793     /// # Examples
794     ///
795     /// ```
796     /// use tonic_types::{ErrorDetails, HelpLink};
797     ///
798     /// let mut err_details = ErrorDetails::new();
799     ///
800     /// err_details.set_help(vec![
801     ///     HelpLink::new("description of link a", "resource-a.example.local"),
802     ///     HelpLink::new("description of link b", "resource-b.example.local"),
803     /// ]);
804     /// ```
set_help(&mut self, links: impl Into<Vec<HelpLink>>) -> &mut Self805     pub fn set_help(&mut self, links: impl Into<Vec<HelpLink>>) -> &mut Self {
806         self.help = Some(Help::new(links));
807         self
808     }
809 
810     /// Adds a [`HelpLink`] to [`Help`] details. Sets [`Help`] details if it is
811     /// not set yet. Can be chained with other `.set_` and `.add_`
812     /// [`ErrorDetails`] methods.
813     ///
814     /// # Examples
815     ///
816     /// ```
817     /// use tonic_types::ErrorDetails;
818     ///
819     /// let mut err_details = ErrorDetails::new();
820     ///
821     /// err_details.add_help_link("description of link", "resource.example.local");
822     /// ```
add_help_link( &mut self, description: impl Into<String>, url: impl Into<String>, ) -> &mut Self823     pub fn add_help_link(
824         &mut self,
825         description: impl Into<String>,
826         url: impl Into<String>,
827     ) -> &mut Self {
828         match &mut self.help {
829             Some(help) => {
830                 help.add_link(description, url);
831             }
832             None => {
833                 self.help = Some(Help::with_link(description, url));
834             }
835         };
836         self
837     }
838 
839     /// Returns `true` if [`Help`] is set and its `links` vector is not empty,
840     /// otherwise returns `false`.
841     ///
842     /// # Examples
843     ///
844     /// ```
845     /// use tonic_types::ErrorDetails;
846     ///
847     /// let mut err_details = ErrorDetails::with_help(vec![]);
848     ///
849     /// assert_eq!(err_details.has_help_links(), false);
850     ///
851     /// err_details.add_help_link("description of link", "resource.example.local");
852     ///
853     /// assert_eq!(err_details.has_help_links(), true);
854     /// ```
has_help_links(&self) -> bool855     pub fn has_help_links(&self) -> bool {
856         if let Some(help) = &self.help {
857             return !help.links.is_empty();
858         }
859         false
860     }
861 
862     /// Set [`LocalizedMessage`] details. Can be chained with other `.set_` and
863     /// `.add_` [`ErrorDetails`] methods.
864     ///
865     /// # Examples
866     ///
867     /// ```
868     /// use tonic_types::ErrorDetails;
869     ///
870     /// let mut err_details = ErrorDetails::new();
871     ///
872     /// err_details.set_localized_message("en-US", "message for the user");
873     /// ```
set_localized_message( &mut self, locale: impl Into<String>, message: impl Into<String>, ) -> &mut Self874     pub fn set_localized_message(
875         &mut self,
876         locale: impl Into<String>,
877         message: impl Into<String>,
878     ) -> &mut Self {
879         self.localized_message = Some(LocalizedMessage::new(locale, message));
880         self
881     }
882 }
883