|  | //   Copyright 2015 Colin Sherratt | 
|  | // | 
|  | //   Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | //   you may not use this file except in compliance with the License. | 
|  | //   You may obtain a copy of the License at | 
|  | // | 
|  | //       http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | //   Unless required by applicable law or agreed to in writing, software | 
|  | //   distributed under the License is distributed on an "AS IS" BASIS, | 
|  | //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | //   See the License for the specific language governing permissions and | 
|  | //   limitations under the License. | 
|  |  | 
|  |  | 
|  | use std::sync::{Arc, Mutex}; | 
|  | use std::collections::HashMap; | 
|  | use {Signal, ArmedSignal, Pulse, Waiting, Barrier, Signals}; | 
|  |  | 
|  | pub struct Inner { | 
|  | pub ready: Vec<usize>, | 
|  | pub trigger: Option<Pulse>, | 
|  | } | 
|  |  | 
|  | pub struct Handle(pub Arc<Mutex<Inner>>); | 
|  |  | 
|  | /// A `Select` listens to 1 or more signals. It will wait until | 
|  | /// any signal becomes available before Pulsing. `Select` will then | 
|  | /// return the `Signal` that has been `Pulsed`. `Select` has no defined | 
|  | /// ordering of events for `Signal`s when there are more then one `Signals` | 
|  | /// pending. | 
|  | pub struct Select { | 
|  | inner: Arc<Mutex<Inner>>, | 
|  | signals: HashMap<usize, ArmedSignal>, | 
|  | } | 
|  |  | 
|  | impl Select { | 
|  | /// Create a new empty `Select` | 
|  | pub fn new() -> Select { | 
|  | Select { | 
|  | inner: Arc::new(Mutex::new(Inner { | 
|  | ready: Vec::new(), | 
|  | trigger: None, | 
|  | })), | 
|  | signals: HashMap::new(), | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Add a signal to the `Select`, a unique id that is associated | 
|  | /// With the signal is returned. This can be used to remove the | 
|  | /// signal from the `Select` or to lookup the `Pulse` when it fires. | 
|  | pub fn add(&mut self, pulse: Signal) -> usize { | 
|  | let id = pulse.id(); | 
|  | let p = pulse.arm(Waiting::select(Handle(self.inner.clone()))); | 
|  | self.signals.insert(id, p); | 
|  | id | 
|  | } | 
|  |  | 
|  | /// Remove a `Signal1 from the `Select` using it's unique id. | 
|  | pub fn remove(&mut self, id: usize) -> Option<Signal> { | 
|  | self.signals | 
|  | .remove(&id) | 
|  | .map(|x| x.disarm()) | 
|  | } | 
|  |  | 
|  | /// Convert all the signals present in the `Select` into a `Barrier` | 
|  | pub fn into_barrier(self) -> Barrier { | 
|  | let vec: Vec<Signal> = self.signals | 
|  | .into_iter() | 
|  | .map(|(_, p)| p.disarm()) | 
|  | .collect(); | 
|  |  | 
|  | Barrier::new(&vec) | 
|  | } | 
|  |  | 
|  | /// This is a non-blocking attempt to get a `Signal` from a `Select` | 
|  | /// this will return a `Some(Signal)` if there is a pending `Signal` | 
|  | /// in the select. Otherwise it will return `None` | 
|  | pub fn try_next(&mut self) -> Option<Signal> { | 
|  | let mut guard = self.inner.lock().unwrap(); | 
|  | if let Some(x) = guard.ready.pop() { | 
|  | return Some(self.signals.remove(&x).map(|x| x.disarm()).unwrap()); | 
|  | } | 
|  | None | 
|  | } | 
|  |  | 
|  | /// Get the number of Signals being watched | 
|  | pub fn len(&self) -> usize { | 
|  | self.signals.len() | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Iterator for Select { | 
|  | type Item = Signal; | 
|  |  | 
|  | fn next(&mut self) -> Option<Signal> { | 
|  | loop { | 
|  | if self.signals.len() == 0 { | 
|  | return None; | 
|  | } | 
|  |  | 
|  | let pulse = { | 
|  | let mut guard = self.inner.lock().unwrap(); | 
|  | while let Some(x) = guard.ready.pop() { | 
|  | if let Some(x) = self.signals.remove(&x) { | 
|  | return Some(x.disarm()); | 
|  | } | 
|  | } | 
|  | let (pulse, t) = Signal::new(); | 
|  | guard.trigger = Some(t); | 
|  | pulse | 
|  | }; | 
|  | pulse.wait().unwrap(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Signals for Select { | 
|  | fn signal(&self) -> Signal { | 
|  | let (pulse, t) = Signal::new(); | 
|  | let mut guard = self.inner.lock().unwrap(); | 
|  | if guard.ready.len() == 0 { | 
|  | guard.trigger = Some(t); | 
|  | } else { | 
|  | t.pulse(); | 
|  | } | 
|  | pulse | 
|  | } | 
|  | } | 
|  |  | 
|  | /// `SelectMap` is a wrapper around a `Select` rather then use | 
|  | /// a unique id to find out what signal has been asserts, `SelectMap` | 
|  | /// will return an supplied object. | 
|  | pub struct SelectMap<T> { | 
|  | select: Select, | 
|  | items: HashMap<usize, T>, | 
|  | } | 
|  |  | 
|  | impl<T> SelectMap<T> { | 
|  | /// Create a new empty `SelectMap` | 
|  | pub fn new() -> SelectMap<T> { | 
|  | SelectMap { | 
|  | select: Select::new(), | 
|  | items: HashMap::new(), | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Add a `Signal` and an associated value into the `SelectMap` | 
|  | pub fn add(&mut self, signal: Signal, value: T) { | 
|  | let id = self.select.add(signal); | 
|  | self.items.insert(id, value); | 
|  | } | 
|  |  | 
|  | /// This is a non-blocking attempt to get a `Signal` from a `SelectMap` | 
|  | /// this will return a `Some((Signal, T))` if there is a pending `Signal` | 
|  | /// in the select. Otherwise it will return `None` | 
|  | pub fn try_next(&mut self) -> Option<(Signal, T)> { | 
|  | self.select.try_next().map(|x| { | 
|  | let id = x.id(); | 
|  | (x, self.items.remove(&id).unwrap()) | 
|  | }) | 
|  | } | 
|  |  | 
|  | /// Get the number of items in the `SelectMap` | 
|  | pub fn len(&self) -> usize { | 
|  | self.items.len() | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<T> Iterator for SelectMap<T> { | 
|  | type Item = (Signal, T); | 
|  |  | 
|  | fn next(&mut self) -> Option<(Signal, T)> { | 
|  | self.select.next().map(|x| { | 
|  | let id = x.id(); | 
|  | (x, self.items.remove(&id).unwrap()) | 
|  | }) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<T> Signals for SelectMap<T> { | 
|  | fn signal(&self) -> Signal { | 
|  | self.select.signal() | 
|  | } | 
|  | } |