// TODO: Fill in the missing methods for `TicketStore`. // Notice how we no longer need a separate update command: `Get` now returns a handle to the ticket // which allows the caller to both modify and read the ticket. use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError}; use std::sync::{Arc, Mutex}; use crate::data::{Ticket, TicketDraft}; use crate::store::{TicketId, TicketStore}; pub mod data; pub mod store; #[derive(Clone)] pub struct TicketStoreClient { sender: SyncSender, } impl TicketStoreClient { pub fn insert(&self, draft: TicketDraft) -> Result> { let (response_sender, response_receiver) = sync_channel(1); self.sender.try_send(Command::Insert { draft, response_channel: response_sender, })?; Ok(response_receiver.recv().unwrap()) } pub fn get(&self, id: TicketId) -> Result>>, TrySendError> { let (response_sender, response_receiver) = sync_channel(1); self.sender.try_send(Command::Get { id, response_channel: response_sender, })?; Ok(response_receiver.recv().unwrap()) } } pub fn launch(capacity: usize) -> TicketStoreClient { let (sender, receiver) = sync_channel(capacity); std::thread::spawn(move || server(receiver)); TicketStoreClient { sender } } enum Command { Insert { draft: TicketDraft, response_channel: SyncSender, }, Get { id: TicketId, response_channel: SyncSender>>>, }, } pub fn server(receiver: Receiver) { let mut store = TicketStore::new(); loop { match receiver.recv() { Ok(Command::Insert { draft, response_channel, }) => { let id = store.add_ticket(draft); let _ = response_channel.send(id); } Ok(Command::Get { id, response_channel, }) => { let ticket = store.get(id); let _ = response_channel.send(ticket); } Err(_) => { // There are no more senders, so we can safely break // and shut down the server. break; } } } }