From ed658d6016ce71148e8673b9ca76c01fb0267e32 Mon Sep 17 00:00:00 2001 From: Colin Rofls Date: Wed, 2 Sep 2020 13:48:25 -0400 Subject: [PATCH] Add MissingKeyError to Env This is a little bit of cleanup while I was looking into making another addition to the env. This is technically a breaking change (we return Result instead of Option) but these API are not heavily used and I'm not too concerned about the breakage. --- CHANGELOG.md | 3 +++ druid/src/env.rs | 69 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7032fd26fc..17599edd7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ You can find its changes [documented below](#060---2020-06-01). - `Container::rounded` takes `KeyOrValue` instead of `f64`. ([#1054] by [@binomial0]) - `request_anim_frame` no longer invalidates the entire window. ([#1057] by [@jneem]) - Use new Piet text api ([#1143] by [@cmyr]) +- `Env::try_get` (and related methods) return a `Result` instead of an `Option`. + ([#1172] by [@cmyr]) ### Deprecated @@ -403,6 +405,7 @@ Last release without a changelog :( [#1151]: https://github.com/linebender/druid/pull/1151 [#1152]: https://github.com/linebender/druid/pull/1152 [#1157]: https://github.com/linebender/druid/pull/1157 +[#1172]: https://github.com/linebender/druid/pull/1157 [Unreleased]: https://github.com/linebender/druid/compare/v0.6.0...master [0.6.0]: https://github.com/linebender/druid/compare/v0.5.0...v0.6.0 diff --git a/druid/src/env.rs b/druid/src/env.rs index e51bb6ff54..e3d13693b9 100644 --- a/druid/src/env.rs +++ b/druid/src/env.rs @@ -156,6 +156,16 @@ pub struct ValueTypeError { found: Value, } +/// An error type for when a key is missing from the [`Env`]. +/// +/// [`Env`]: struct.Env.html +#[derive(Debug, Clone)] +#[non_exhaustive] +pub struct MissingKeyError { + /// The raw key. + key: Arc, +} + impl Env { /// State for whether or not to paint colorful rectangles for layout /// debugging. @@ -205,24 +215,30 @@ impl Env { /// /// Panics if the key is not found, or if it is present with the wrong type. pub fn get<'a, V: ValueType<'a>>(&'a self, key: impl Borrow>) -> V { - let key = key.borrow(); - if let Some(value) = self.0.map.get(key.key) { - value.to_inner_unchecked() - } else { - panic!("key for {} not found", key.key) + match self.try_get(key) { + Ok(value) => value, + Err(err) => panic!("{}", err), } } - /// Gets a value from the environment. + /// Trys to get a value from the environment. + /// + /// If the value is not found, the raw key is returned as the error. /// /// # Panics /// /// Panics if the value for the key is found, but has the wrong type. - pub fn try_get<'a, V: ValueType<'a>>(&'a self, key: impl Borrow>) -> Option { + pub fn try_get<'a, V: ValueType<'a>>( + &'a self, + key: impl Borrow>, + ) -> Result { self.0 .map .get(key.borrow().key) .map(|value| value.to_inner_unchecked()) + .ok_or(MissingKeyError { + key: key.borrow().key.into(), + }) } /// Gets a value from the environment, in its encapsulated [`Value`] form, @@ -233,25 +249,28 @@ impl Env { /// /// # Panics /// - /// Panics if the key is not found + /// Panics if the key is not found. + /// /// [`Value`]: enum.Value.html pub fn get_untyped(&self, key: impl Borrow>) -> &Value { - let key = key.borrow(); - if let Some(value) = self.0.map.get(key.key) { - value - } else { - panic!("key for {} not found", key.key) + match self.try_get_untyped(key) { + Ok(val) => val, + Err(err) => panic!("{}", err), } } /// Gets a value from the environment, in its encapsulated [`Value`] form, - /// returning None if a value isn't found. + /// returning `None` if a value isn't found. + /// + /// # Note + /// This is not intended for general use, but only for inspecting an `Env` + /// e.g. for debugging, theme editing, and theme loading. /// - /// *WARNING:* This is not intended for general use, but only for inspecting an `Env` e.g. - /// for debugging, theme editing, and theme loading. /// [`Value`]: enum.Value.html - pub fn try_get_untyped(&self, key: impl Borrow>) -> Option<&Value> { - self.0.map.get(key.borrow().key) + pub fn try_get_untyped(&self, key: impl Borrow>) -> Result<&Value, MissingKeyError> { + self.0.map.get(key.borrow().key).ok_or(MissingKeyError { + key: key.borrow().key.into(), + }) } /// Gets the entire contents of the `Env`, in key-value pairs. @@ -484,7 +503,21 @@ impl std::fmt::Display for ValueTypeError { } } +impl MissingKeyError { + /// The raw key that was missing. + pub fn raw_key(&self) -> &str { + &self.key + } +} + +impl std::fmt::Display for MissingKeyError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Missing key: '{}'", self.key) + } +} + impl std::error::Error for ValueTypeError {} +impl std::error::Error for MissingKeyError {} /// Use this macro for types which are cheap to clone (ie all `Copy` types). macro_rules! impl_value_type_owned {