diff --git a/Cargo.lock b/Cargo.lock index c92bc37..412a0f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -205,6 +205,7 @@ dependencies = [ name = "bounded" version = "0.1.0" dependencies = [ + "thiserror", "ticket_fields", ] diff --git a/exercises/07_threads/08_client/src/lib.rs b/exercises/07_threads/08_client/src/lib.rs index a934bd3..f716521 100644 --- a/exercises/07_threads/08_client/src/lib.rs +++ b/exercises/07_threads/08_client/src/lib.rs @@ -7,23 +7,38 @@ pub mod store; #[derive(Clone)] // TODO: flesh out the client implementation. -pub struct TicketStoreClient {} +pub struct TicketStoreClient { + sender: Sender, +} impl TicketStoreClient { // Feel free to panic on all errors, for simplicity. pub fn insert(&self, draft: TicketDraft) -> TicketId { - todo!() + let (sendr, recvr) = std::sync::mpsc::channel::(); + match self.sender.send(Command::Insert { + draft: draft, + response_channel: sendr, + }) { + Ok(a) => {} + _ => {} + } + recvr.recv().ok().unwrap() } pub fn get(&self, id: TicketId) -> Option { - todo!() + let (sendr, recvr) = std::sync::mpsc::channel::>(); + self.sender.send(Command::Get { + id: id, + response_channel: sendr, + }); + recvr.recv().unwrap() } } pub fn launch() -> TicketStoreClient { let (sender, receiver) = std::sync::mpsc::channel(); std::thread::spawn(move || server(receiver)); - todo!() + TicketStoreClient { sender } } // No longer public! This becomes an internal detail of the library now. diff --git a/exercises/07_threads/09_bounded/Cargo.toml b/exercises/07_threads/09_bounded/Cargo.toml index 506d14a..91aec93 100644 --- a/exercises/07_threads/09_bounded/Cargo.toml +++ b/exercises/07_threads/09_bounded/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] ticket_fields = { path = "../../../helpers/ticket_fields" } +thiserror="* " diff --git a/exercises/07_threads/09_bounded/src/lib.rs b/exercises/07_threads/09_bounded/src/lib.rs index e661e68..7c29c56 100644 --- a/exercises/07_threads/09_bounded/src/lib.rs +++ b/exercises/07_threads/09_bounded/src/lib.rs @@ -1,40 +1,58 @@ // TODO: Convert the implementation to use bounded channels. use crate::data::{Ticket, TicketDraft}; use crate::store::{TicketId, TicketStore}; -use std::sync::mpsc::{Receiver, Sender}; +use std::sync::mpsc::{Receiver, Sender, SyncSender}; pub mod data; pub mod store; #[derive(Clone)] pub struct TicketStoreClient { - sender: todo!(), + sender: SyncSender, } +#[derive(Debug, thiserror::Error)] +#[error("Server is overloaded")] +pub struct OverLoadedError; + impl TicketStoreClient { - pub fn insert(&self, draft: TicketDraft) -> Result { - todo!() + pub fn insert(&self, draft: TicketDraft) -> Result { + let (sender, receiver) = std::sync::mpsc::sync_channel(1); + self.sender + .try_send(Command::Insert { + draft, + response_channel: sender, + }) + .map_err(|_| OverLoadedError); + Ok(receiver.recv().unwrap()) } - pub fn get(&self, id: TicketId) -> Result, todo!()> { - todo!() + pub fn get(&self, id: TicketId) -> Result, OverLoadedError> { + let (sender, receiver) = std::sync::mpsc::sync_channel(1); + self.sender + .try_send(Command::Get { + id, + response_channel: sender, + }) + .map_err(|_| OverLoadedError); + Ok(receiver.recv().unwrap()) } } pub fn launch(capacity: usize) -> TicketStoreClient { - todo!(); + let (sender, receiver) = std::sync::mpsc::sync_channel(capacity); std::thread::spawn(move || server(receiver)); - todo!() + TicketStoreClient { sender } } enum Command { Insert { draft: TicketDraft, - response_channel: todo!(), + response_channel: SyncSender, }, Get { id: TicketId, - response_channel: todo!(), + response_channel: SyncSender>, }, } @@ -47,14 +65,14 @@ pub fn server(receiver: Receiver) { response_channel, }) => { let id = store.add_ticket(draft); - todo!() + response_channel.send(id); } Ok(Command::Get { id, response_channel, }) => { let ticket = store.get(id); - todo!() + response_channel.send(ticket.cloned()); } Err(_) => { // There are no more senders, so we can safely break diff --git a/exercises/07_threads/10_patch/src/lib.rs b/exercises/07_threads/10_patch/src/lib.rs index 492f767..e5cbb4b 100644 --- a/exercises/07_threads/10_patch/src/lib.rs +++ b/exercises/07_threads/10_patch/src/lib.rs @@ -35,7 +35,15 @@ impl TicketStoreClient { Ok(response_receiver.recv().unwrap()) } - pub fn update(&self, ticket_patch: TicketPatch) -> Result<(), OverloadedError> {} + pub fn update(&self, ticket_patch: TicketPatch) -> Result<(), OverloadedError> { + let (sender, receiver) = sync_channel(1); + self.sender + .try_send(Command::Update { + patch: ticket_patch, + response_channel: sender, + }) + .map_err(|_| OverloadedError) + } } #[derive(Debug, thiserror::Error)] @@ -85,7 +93,23 @@ pub fn server(receiver: Receiver) { patch, response_channel, }) => { - todo!() + let ticket = store.get_mut(patch.id).unwrap(); + match patch.title { + Some(a) => { + ticket.title = a; + } + None => {} + } + + match patch.status { + Some(a) => ticket.status = a, + None => {} + } + + match patch.description { + Some(a) => ticket.description = a, + None => {} + } } Err(_) => { // There are no more senders, so we can safely break diff --git a/exercises/07_threads/11_locks/src/store.rs b/exercises/07_threads/11_locks/src/store.rs index 9387499..306e662 100644 --- a/exercises/07_threads/11_locks/src/store.rs +++ b/exercises/07_threads/11_locks/src/store.rs @@ -28,13 +28,13 @@ impl TicketStore { description: ticket.description, status: Status::ToDo, }; - todo!(); + self.tickets.insert(id, Arc::new(Mutex::new(ticket))); id } // The `get` method should return a handle to the ticket // which allows the caller to either read or modify the ticket. - pub fn get(&self, id: TicketId) -> Option { - todo!() + pub fn get(&self, id: TicketId) -> Option>> { + self.tickets.get(&id).cloned() } } diff --git a/exercises/07_threads/12_rw_lock/src/lib.rs b/exercises/07_threads/12_rw_lock/src/lib.rs index 0c33f53..fd7a338 100644 --- a/exercises/07_threads/12_rw_lock/src/lib.rs +++ b/exercises/07_threads/12_rw_lock/src/lib.rs @@ -1,7 +1,7 @@ // TODO: Replace `Mutex` with `RwLock` in the `TicketStore` struct and // all other relevant places to allow multiple readers to access the ticket store concurrently. use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError}; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use crate::data::{Ticket, TicketDraft}; use crate::store::{TicketId, TicketStore}; @@ -26,7 +26,7 @@ impl TicketStoreClient { Ok(response_receiver.recv().unwrap()) } - pub fn get(&self, id: TicketId) -> Result>>, OverloadedError> { + pub fn get(&self, id: TicketId) -> Result>>, OverloadedError> { let (response_sender, response_receiver) = sync_channel(1); self.sender .try_send(Command::Get { @@ -55,7 +55,7 @@ enum Command { }, Get { id: TicketId, - response_channel: SyncSender>>>, + response_channel: SyncSender>>>, }, } diff --git a/exercises/07_threads/12_rw_lock/src/store.rs b/exercises/07_threads/12_rw_lock/src/store.rs index 7387efd..f29ed7a 100644 --- a/exercises/07_threads/12_rw_lock/src/store.rs +++ b/exercises/07_threads/12_rw_lock/src/store.rs @@ -1,13 +1,13 @@ use crate::data::{Status, Ticket, TicketDraft}; use std::collections::BTreeMap; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct TicketId(u64); #[derive(Clone)] pub struct TicketStore { - tickets: BTreeMap>>, + tickets: BTreeMap>>, counter: u64, } @@ -28,14 +28,14 @@ impl TicketStore { description: ticket.description, status: Status::ToDo, }; - let ticket = Arc::new(Mutex::new(ticket)); + let ticket = Arc::new(RwLock::new(ticket)); self.tickets.insert(id, ticket); id } // The `get` method should return a handle to the ticket // which allows the caller to either read or modify the ticket. - pub fn get(&self, id: TicketId) -> Option>> { + pub fn get(&self, id: TicketId) -> Option>> { self.tickets.get(&id).cloned() } } diff --git a/exercises/07_threads/13_without_channels/tests/check.rs b/exercises/07_threads/13_without_channels/tests/check.rs index e0d9c88..a915761 100644 --- a/exercises/07_threads/13_without_channels/tests/check.rs +++ b/exercises/07_threads/13_without_channels/tests/check.rs @@ -7,7 +7,7 @@ use without_channels::store::TicketStore; #[test] fn works() { - let store = todo!(); + let store = Arc::new(RwLock::new(TicketStore::new())); let store1 = store.clone(); let client1 = spawn(move || { diff --git a/exercises/07_threads/14_sync/src/lib.rs b/exercises/07_threads/14_sync/src/lib.rs index c67d0f7..b698498 100644 --- a/exercises/07_threads/14_sync/src/lib.rs +++ b/exercises/07_threads/14_sync/src/lib.rs @@ -1,6 +1,6 @@ // Not much to be exercised on `Sync`, just a thing to remember. fn outro() -> &'static str { - "I have a good understanding of __!" + "I have a good understanding of Send and Sync!" } #[cfg(test)] diff --git a/exercises/08_futures/00_intro/src/lib.rs b/exercises/08_futures/00_intro/src/lib.rs index c730220..d464426 100644 --- a/exercises/08_futures/00_intro/src/lib.rs +++ b/exercises/08_futures/00_intro/src/lib.rs @@ -1,6 +1,6 @@ fn intro() -> &'static str { // TODO: fix me 👇 - "I'm ready to _!" + "I'm ready to learn about futures!" } #[cfg(test)]