hyper-server: Initial version
[learn-rust.git] / simple-http / src / lib.rs
1 use std::thread;
2 use std::sync::{Arc, mpsc, Mutex};
3
4 type Job = Box<dyn FnOnce() + Send + 'static>;
5
6 enum Message {
7     NewJob(Job),
8     Terminate,
9 }
10
11 struct Worker {
12     id: usize,
13     thread: Option<thread::JoinHandle<()>>,
14 }
15
16 impl Worker {
17     fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
18         let thread = Some(thread::spawn(move || loop {
19             let message = receiver.lock().unwrap().recv().unwrap();
20
21             match message {
22                 Message::NewJob(job) => {
23                     println!("Worker {} got a job, executing", id);
24                     job();
25                 },
26
27                 Message::Terminate => {
28                     println!("Worker {} got terminated", id);
29                     break;
30                 }
31             }
32         }));
33         Worker { id, thread }
34     }
35 }
36
37 pub struct ThreadPool {
38     workers: Vec<Worker>,
39     sender: mpsc::Sender<Message>,
40 }
41
42 impl ThreadPool {
43     /// Create a new thread pool.
44     ///
45     /// # Panics
46     ///
47     /// - if size is zero
48     pub fn new(size: usize) -> ThreadPool {
49         assert!(size > 0);
50         let mut workers = Vec::with_capacity(size);
51
52         let (sender, receiver) = mpsc::channel();
53         let receiver = Arc::new(Mutex::new(receiver));
54
55         for id in 0..size {
56             workers.push(Worker::new(id, Arc::clone(&receiver)));
57         }
58
59         ThreadPool { workers, sender }
60     }
61
62     pub fn execute<F>(&self, f: F)
63     where F: FnOnce() + Send + 'static
64     {
65         self.sender.send(Message::NewJob(Box::new(f))).unwrap();
66     }
67 }
68
69 impl Drop for ThreadPool {
70     fn drop(&mut self) {
71         for _ in &self.workers {
72             self.sender.send(Message::Terminate).unwrap();
73         }
74
75         for worker in &mut self.workers {
76             println!("Shutting down worker {}", worker.id);
77
78             if let Some(thread) = worker.thread.take() {
79                 thread.join().unwrap();
80             }
81         }
82     }
83 }