webrtc_constraints/
errors.rs1use std::collections::HashMap;
6
7use crate::{
8 algorithms::{ConstraintFailureInfo, SettingFitnessDistanceErrorKind},
9 MediaTrackProperty,
10};
11
12#[derive(Clone, Eq, PartialEq, Debug)]
14pub struct OverconstrainedError {
15 pub constraint: MediaTrackProperty,
17 pub message: Option<String>,
19}
20
21impl Default for OverconstrainedError {
22 fn default() -> Self {
23 Self {
24 constraint: MediaTrackProperty::from(""),
25 message: Default::default(),
26 }
27 }
28}
29
30impl std::fmt::Display for OverconstrainedError {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 write!(f, "Overconstrained property {:?}", self.constraint)?;
33 if let Some(message) = self.message.as_ref() {
34 write!(f, ": {}", message)?;
35 }
36 Ok(())
37 }
38}
39
40impl std::error::Error for OverconstrainedError {}
41
42impl OverconstrainedError {
43 pub(super) fn exposing_device_information(
44 failed_constraints: HashMap<MediaTrackProperty, ConstraintFailureInfo>,
45 ) -> Self {
46 let failed_constraint = failed_constraints
47 .into_iter()
48 .max_by_key(|(_, failure_info)| failure_info.failures);
49
50 let (constraint, failure_info) =
51 failed_constraint.expect("Empty candidates implies non-empty failed constraints");
52
53 struct Violation {
54 constraint: String,
55 settings: Vec<String>,
56 }
57 let mut violators_by_kind: HashMap<SettingFitnessDistanceErrorKind, Violation> =
58 HashMap::default();
59
60 for error in failure_info.errors {
61 let violation = violators_by_kind.entry(error.kind).or_insert(Violation {
62 constraint: error.constraint.clone(),
63 settings: vec![],
64 });
65 assert_eq!(violation.constraint, error.constraint);
66 if let Some(setting) = error.setting {
67 violation.settings.push(setting.clone());
68 }
69 }
70
71 let formatted_reasons: Vec<_> = violators_by_kind
72 .into_iter()
73 .map(|(kind, violation)| {
74 let kind_str = match kind {
75 SettingFitnessDistanceErrorKind::Missing => "missing",
76 SettingFitnessDistanceErrorKind::Mismatch => "a mismatch",
77 SettingFitnessDistanceErrorKind::TooSmall => "too small",
78 SettingFitnessDistanceErrorKind::TooLarge => "too large",
79 };
80
81 let mut settings = violation.settings;
82
83 if settings.is_empty() {
84 return format!("{} (does not satisfy {})", kind_str, violation.constraint);
85 }
86
87 settings.sort();
88
89 format!(
90 "{} ([{}] do not satisfy {})",
91 kind_str,
92 settings.join(", "),
93 violation.constraint
94 )
95 })
96 .collect();
97
98 let formatted_reason = match &formatted_reasons[..] {
99 [] => unreachable!(),
100 [reason] => reason.clone(),
101 [reasons @ .., reason] => {
102 let reasons = reasons.join(", ");
103 format!("either {}, or {}", reasons, reason)
104 }
105 };
106 let message = Some(format!("Setting was {}.", formatted_reason));
107
108 Self {
109 constraint,
110 message,
111 }
112 }
113}