From b6d0269867332a6be738aa7136d2d68c699d52db Mon Sep 17 00:00:00 2001 From: Pat Pannuto Date: Sun, 1 Jul 2018 14:04:42 -0700 Subject: [PATCH 1/7] tock-cells: add `and_then` for OptionalCell Mirrors https://doc.rust-lang.org/std/option/enum.Option.html#method.and_then --- libraries/tock-cells/src/optional_cell.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/tock-cells/src/optional_cell.rs b/libraries/tock-cells/src/optional_cell.rs index 574c8225a8..053820daee 100644 --- a/libraries/tock-cells/src/optional_cell.rs +++ b/libraries/tock-cells/src/optional_cell.rs @@ -80,4 +80,10 @@ impl OptionalCell { .get() .map_or_else(default, |mut val| closure(&mut val)) } + + /// If the cell is empty, return `None`. Otherwise, call a closure + /// with the value of the cell and return the result. + pub fn and_then Option>(&self, f: F) -> Option { + self.value.get().and_then(f) + } } From d3428193a32ae7412ea2dce27b295d1f53fba1fb Mon Sep 17 00:00:00 2001 From: Pat Pannuto Date: Sun, 1 Jul 2018 14:05:27 -0700 Subject: [PATCH 2/7] tock-cells: Add `replace` method to `OptionalCell` Sometimes you have an `Option` that you'd like to put in an `OptionalCell`, which means you need to either `set` or `clear` to `OptionalCell` depending on the `Option` you're putting in. This implements that logic in `OptionalCell`. --- libraries/tock-cells/src/optional_cell.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libraries/tock-cells/src/optional_cell.rs b/libraries/tock-cells/src/optional_cell.rs index 053820daee..5e9ca51720 100644 --- a/libraries/tock-cells/src/optional_cell.rs +++ b/libraries/tock-cells/src/optional_cell.rs @@ -44,6 +44,15 @@ impl OptionalCell { self.value.set(None); } + /// Replace the contents with the value from the supplied `Option`, + /// or empty this `OptionalCell` if the supplied `Option` is `None`. + pub fn replace(&self, option: Option) { + match option { + Some(v) => self.set(v), + None => self.clear(), + } + } + /// Return the contained value and replace it with None. pub fn take(&self) -> Option { self.value.take() From 976c9c9229942495fbde0dad647eacf97e84ce62 Mon Sep 17 00:00:00 2001 From: Pat Pannuto Date: Sun, 1 Jul 2018 14:46:34 -0700 Subject: [PATCH 3/7] tock-cells: add `expect` method Mirrors https://doc.rust-lang.org/std/option/enum.Option.html#method.expect --- libraries/tock-cells/src/optional_cell.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/tock-cells/src/optional_cell.rs b/libraries/tock-cells/src/optional_cell.rs index 5e9ca51720..c4be7f30d9 100644 --- a/libraries/tock-cells/src/optional_cell.rs +++ b/libraries/tock-cells/src/optional_cell.rs @@ -53,6 +53,11 @@ impl OptionalCell { } } + /// Returns the contained value, or panics if contents is `None`. + pub fn expect(&self, msg: &str) -> T { + self.value.get().expect(msg) + } + /// Return the contained value and replace it with None. pub fn take(&self) -> Option { self.value.take() From 2a1492a45993953fa521694bb134ccac8b0e0815 Mon Sep 17 00:00:00 2001 From: Pat Pannuto Date: Mon, 2 Jul 2018 21:22:47 -0700 Subject: [PATCH 4/7] tock-cells: add remaining `Option` methods Add the remaining methods from std `Option` that are sensical for `OptionalCell`. --- libraries/tock-cells/Cargo.lock | 7 -- libraries/tock-cells/src/optional_cell.rs | 121 ++++++++++++++++++---- 2 files changed, 102 insertions(+), 26 deletions(-) diff --git a/libraries/tock-cells/Cargo.lock b/libraries/tock-cells/Cargo.lock index 1017c255e3..5c429b61b2 100644 --- a/libraries/tock-cells/Cargo.lock +++ b/libraries/tock-cells/Cargo.lock @@ -1,11 +1,4 @@ [[package]] name = "tock-cells" version = "0.1.0" -dependencies = [ - "tock-regs 0.1.0", -] - -[[package]] -name = "tock-regs" -version = "0.1.0" diff --git a/libraries/tock-cells/src/optional_cell.rs b/libraries/tock-cells/src/optional_cell.rs index c4be7f30d9..a5ed68ab57 100644 --- a/libraries/tock-cells/src/optional_cell.rs +++ b/libraries/tock-cells/src/optional_cell.rs @@ -24,26 +24,11 @@ impl OptionalCell { } } - /// Check if the cell is None. - pub fn is_none(&self) -> bool { - self.value.get().is_none() - } - - /// Check if the cell contains something. - pub fn is_some(&self) -> bool { - self.value.get().is_some() - } - /// Update the stored value. pub fn set(&self, val: T) { self.value.set(Some(val)); } - /// Reset the stored value to `None`. - pub fn clear(&self) { - self.value.set(None); - } - /// Replace the contents with the value from the supplied `Option`, /// or empty this `OptionalCell` if the supplied `Option` is `None`. pub fn replace(&self, option: Option) { @@ -53,14 +38,42 @@ impl OptionalCell { } } - /// Returns the contained value, or panics if contents is `None`. + /// Reset the stored value to `None`. + pub fn clear(&self) { + self.value.set(None); + } + + /// Check if the cell contains something. + pub fn is_some(&self) -> bool { + self.value.get().is_some() + } + + /// Check if the cell is None. + pub fn is_none(&self) -> bool { + self.value.get().is_none() + } + + /// Returns the contained value or panics if contents is `None`. pub fn expect(&self, msg: &str) -> T { self.value.get().expect(msg) } - /// Return the contained value and replace it with None. - pub fn take(&self) -> Option { - self.value.take() + /// Returns the contained value or panics if contents is `None`. + pub fn unwrap(&self) -> T { + self.value.get().unwrap() + } + + /// Returns the contained value or a default. + pub fn unwrap_or(&self, default: T) -> T { + self.value.get().unwrap_or(default) + } + + /// Returns the contained value or computes a default. + pub fn unwrap_or_else(&self, default: F) -> T + where + F: FnOnce() -> T, + { + self.value.get().unwrap_or_else(default) } /// Call a closure on the value if the value exists. @@ -95,9 +108,79 @@ impl OptionalCell { .map_or_else(default, |mut val| closure(&mut val)) } + /// Transforms the contained `Option` into a `Result`, mapping + /// `Some(v)` to `Ok(v)` and `None` to `Err(err)`. + /// + /// Arguments passed to `ok_or` are eagerly evaluated; if you are passing + /// the result of a function call, it is recommended to use `ok_or_else`, + /// which is lazily evaluated. + pub fn ok_or(self, err: E) -> Result { + self.value.get().ok_or(err) + } + + /// Transforms the contained `Option` into a `Result`, mapping + /// `Some(v)` to `Ok(v)` and `None` to `Err(err)`. + pub fn ok_or_else(self, err: F) -> Result + where + F: FnOnce() -> E, + { + self.value.get().ok_or_else(err) + } + + /// Returns `None` if the option is `None`, otherwise returns `optb`. + pub fn and(self, optb: Option) -> Option { + self.value.get().and(optb) + } + /// If the cell is empty, return `None`. Otherwise, call a closure /// with the value of the cell and return the result. pub fn and_then Option>(&self, f: F) -> Option { self.value.get().and_then(f) } + + /// Returns `None` if the option is `None`, otherwise calls `predicate` with + /// the wrapped value and returns: + /// + /// - `Some(t)` if `predicate` returns `true` (where `t` is the wrapped value), and + /// - `None` if `predicate` returns `false`. + pub fn filter

(self, predicate: P) -> Option + where + P: FnOnce(&T) -> bool, + { + self.value.get().filter(predicate) + } + + /// Returns the option if it contains a value, otherwise returns `optb`. + /// + /// Arguments passed to or are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use `or_else`, which + /// is lazily evaluated. + pub fn or(self, optb: Option) -> Option { + self.value.get().or(optb) + } + + /// Returns the option if it contains a value, otherwise calls `f` and + /// returns the result. + pub fn or_else(self, f: F) -> Option + where + F: FnOnce() -> Option, + { + self.value.get().or_else(f) + } + + /// Return the contained value and replace it with None. + pub fn take(&self) -> Option { + self.value.take() + } + + /// Returns the contained value or a default + /// + /// Consumes the `self` argument then, if `Some`, returns the contained + /// value, otherwise if `None`, returns the default value for that type. + pub fn unwrap_or_default(self) -> T + where + T: Default, + { + self.value.get().unwrap_or_default() + } } From 3cb419b987208b1bb6a8585396fa7ecd3deb982b Mon Sep 17 00:00:00 2001 From: Pat Pannuto Date: Mon, 2 Jul 2018 22:34:21 -0700 Subject: [PATCH 5/7] tock-cells: remove `unwrap` from OptionalCell Don't want to encourage panic'ing method use. --- libraries/tock-cells/src/optional_cell.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/tock-cells/src/optional_cell.rs b/libraries/tock-cells/src/optional_cell.rs index a5ed68ab57..0b6fa8dc6c 100644 --- a/libraries/tock-cells/src/optional_cell.rs +++ b/libraries/tock-cells/src/optional_cell.rs @@ -58,10 +58,8 @@ impl OptionalCell { self.value.get().expect(msg) } - /// Returns the contained value or panics if contents is `None`. - pub fn unwrap(&self) -> T { - self.value.get().unwrap() - } + // Note: Explicitly do not support unwrap, as we do not to encourage + // panic'ing in the Tock kernel. /// Returns the contained value or a default. pub fn unwrap_or(&self, default: T) -> T { From 3dd38eaf7d8dccdee8d3fbebd378eaddb6bc04dd Mon Sep 17 00:00:00 2001 From: Pat Pannuto Date: Mon, 2 Jul 2018 22:37:31 -0700 Subject: [PATCH 6/7] tock-cells: match `replace` for Optional and Take Cells --- libraries/tock-cells/src/optional_cell.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/tock-cells/src/optional_cell.rs b/libraries/tock-cells/src/optional_cell.rs index 0b6fa8dc6c..b2f6381fa4 100644 --- a/libraries/tock-cells/src/optional_cell.rs +++ b/libraries/tock-cells/src/optional_cell.rs @@ -31,11 +31,15 @@ impl OptionalCell { /// Replace the contents with the value from the supplied `Option`, /// or empty this `OptionalCell` if the supplied `Option` is `None`. - pub fn replace(&self, option: Option) { + /// If the cell was not empty, the previous value is returned, otherwise + /// `None` is returned. + pub fn replace(&self, option: Option) -> Option { + let prev = self.take(); match option { Some(v) => self.set(v), None => self.clear(), } + prev } /// Reset the stored value to `None`. From 7426c799ccef8d21b8e9e6f03cd9076468588f7e Mon Sep 17 00:00:00 2001 From: Pat Pannuto Date: Mon, 2 Jul 2018 23:55:53 -0700 Subject: [PATCH 7/7] tock-cells: match `replace` for optional and take cells Introduce `insert` for the new semantics of insering an existing `Option` into an `OptionalCell`. --- libraries/tock-cells/src/optional_cell.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/libraries/tock-cells/src/optional_cell.rs b/libraries/tock-cells/src/optional_cell.rs index b2f6381fa4..e23892720a 100644 --- a/libraries/tock-cells/src/optional_cell.rs +++ b/libraries/tock-cells/src/optional_cell.rs @@ -29,16 +29,21 @@ impl OptionalCell { self.value.set(Some(val)); } - /// Replace the contents with the value from the supplied `Option`, - /// or empty this `OptionalCell` if the supplied `Option` is `None`. - /// If the cell was not empty, the previous value is returned, otherwise - /// `None` is returned. - pub fn replace(&self, option: Option) -> Option { - let prev = self.take(); - match option { + /// Insert the value of the supplied `Option`, or `None` if the supplied + /// `Option` is `None`. + pub fn insert(&self, opt: Option) { + match opt { Some(v) => self.set(v), None => self.clear(), } + } + + /// Replace the contents with the supplied value. + /// If the cell was not empty, the previous value is returned, otherwise + /// `None` is returned. + pub fn replace(&self, val: T) -> Option { + let prev = self.take(); + self.set(val); prev }