diff --git a/CHANGELOG.md b/CHANGELOG.md index ccbb3562ec..8e13dd5849 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,20 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +## [Unreleased] - ReleaseDate +### Added + +- Implemented `Extend`, `FromIterator`, and `IntoIterator` for `SigSet` and + added `SigSet::iter` and `SigSetIter`. + (#[1553](https://github.com/nix-rust/nix/pull/1553)) + +### Changed + +- 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)) + ## [0.23.0] - 2021-09-28 ### Added diff --git a/src/sys/signal.rs b/src/sys/signal.rs index e8c79d3367..6e12684716 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -6,6 +6,9 @@ use crate::{Error, Result}; use crate::errno::Errno; use crate::unistd::Pid; +use std::iter::Extend; +use std::iter::FromIterator; +use std::iter::IntoIterator; use std::mem; use std::fmt; use std::str::FromStr; @@ -500,14 +503,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. @@ -560,6 +558,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)] @@ -1180,6 +1227,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() {