diff --git a/CHANGELOG.md b/CHANGELOG.md index 765ab11a09..942d7b3dac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,12 +47,19 @@ This project adheres to [Semantic Versioning](https://semver.org/). (#[1557](https://github.com/nix-rust/nix/pull/1557)) - Added `nix::uncontext` module on s390x. (#[1662](https://github.com/nix-rust/nix/pull/1662)) +- Implemented `Extend`, `FromIterator`, and `IntoIterator` for `SigSet` and + added `SigSet::iter` and `SigSetIter`. + (#[1553](https://github.com/nix-rust/nix/pull/1553)) ### Changed - `mqueue` functions now operate on a distinct type, `nix::mqueue::MqdT`. Accessors take this type by reference, not by value. (#[1639](https://github.com/nix-rust/nix/pull/1639)) +- Removed `SigSet::extend` in favor of `>::extend`. + Because of this change, you now need `use std::iter::Extend` to call `extend` + on a `SigSet`. + (#[1553](https://github.com/nix-rust/nix/pull/1553)) ### Fixed diff --git a/src/sys/signal.rs b/src/sys/signal.rs index ddc02483ed..f10a213339 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -482,6 +482,9 @@ feature! { #![feature = "signal"] use crate::unistd::Pid; +use std::iter::Extend; +use std::iter::FromIterator; +use std::iter::IntoIterator; /// Specifies a set of [`Signal`]s that may be blocked, waited for, etc. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -532,14 +535,9 @@ impl SigSet { } } - /// Merge all of `other`'s signals into this set. - // TODO: use libc::sigorset on supported operating systems. - pub fn extend(&mut self, other: &SigSet) { - for signal in Signal::iterator() { - if other.contains(signal) { - self.add(signal); - } - } + /// Returns an iterator that yields the signals contained in this set. + pub fn iter(&self) -> SigSetIter<'_> { + self.into_iter() } /// Gets the currently blocked (masked) set of signals for the calling thread. @@ -593,6 +591,55 @@ impl AsRef for SigSet { } } +// TODO: Consider specialization for the case where T is &SigSet and libc::sigorset is available. +impl Extend for SigSet { + fn extend(&mut self, iter: T) + where T: IntoIterator { + for signal in iter { + self.add(signal); + } + } +} + +impl FromIterator for SigSet { + fn from_iter(iter: T) -> Self + where T: IntoIterator { + let mut sigset = SigSet::empty(); + sigset.extend(iter); + sigset + } +} + +/// Iterator for a [`SigSet`]. +/// +/// Call [`SigSet::iter`] to create an iterator. +#[derive(Clone, Debug)] +pub struct SigSetIter<'a> { + sigset: &'a SigSet, + inner: SignalIterator, +} + +impl Iterator for SigSetIter<'_> { + type Item = Signal; + fn next(&mut self) -> Option { + loop { + match self.inner.next() { + None => return None, + Some(signal) if self.sigset.contains(signal) => return Some(signal), + Some(_signal) => continue, + } + } + } +} + +impl<'a> IntoIterator for &'a SigSet { + type Item = Signal; + type IntoIter = SigSetIter<'a>; + fn into_iter(self) -> Self::IntoIter { + SigSetIter { sigset: self, inner: Signal::iterator() } + } +} + /// A signal handler. #[allow(unknown_lints)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -1235,6 +1282,13 @@ mod tests { }).join().unwrap(); } + #[test] + fn test_from_and_into_iterator() { + let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]); + let signals = sigset.into_iter().collect::>(); + assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]); + } + #[test] #[cfg(not(target_os = "redox"))] fn test_sigaction() {