complete chapter 7
This commit is contained in:
@@ -7,23 +7,38 @@ pub mod store;
|
||||
|
||||
#[derive(Clone)]
|
||||
// TODO: flesh out the client implementation.
|
||||
pub struct TicketStoreClient {}
|
||||
pub struct TicketStoreClient {
|
||||
sender: Sender<Command>,
|
||||
}
|
||||
|
||||
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::<TicketId>();
|
||||
match self.sender.send(Command::Insert {
|
||||
draft: draft,
|
||||
response_channel: sendr,
|
||||
}) {
|
||||
Ok(a) => {}
|
||||
_ => {}
|
||||
}
|
||||
recvr.recv().ok().unwrap()
|
||||
}
|
||||
|
||||
pub fn get(&self, id: TicketId) -> Option<Ticket> {
|
||||
todo!()
|
||||
let (sendr, recvr) = std::sync::mpsc::channel::<Option<Ticket>>();
|
||||
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.
|
||||
|
||||
@@ -5,3 +5,4 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
ticket_fields = { path = "../../../helpers/ticket_fields" }
|
||||
thiserror="* "
|
||||
|
||||
@@ -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<Command>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Server is overloaded")]
|
||||
pub struct OverLoadedError;
|
||||
|
||||
impl TicketStoreClient {
|
||||
pub fn insert(&self, draft: TicketDraft) -> Result<TicketId, todo!()> {
|
||||
todo!()
|
||||
pub fn insert(&self, draft: TicketDraft) -> Result<TicketId, OverLoadedError> {
|
||||
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<Option<Ticket>, todo!()> {
|
||||
todo!()
|
||||
pub fn get(&self, id: TicketId) -> Result<Option<Ticket>, 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<TicketId>,
|
||||
},
|
||||
Get {
|
||||
id: TicketId,
|
||||
response_channel: todo!(),
|
||||
response_channel: SyncSender<Option<Ticket>>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -47,14 +65,14 @@ pub fn server(receiver: Receiver<Command>) {
|
||||
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
|
||||
|
||||
@@ -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<Command>) {
|
||||
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
|
||||
|
||||
@@ -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!()> {
|
||||
todo!()
|
||||
pub fn get(&self, id: TicketId) -> Option<Arc<Mutex<Ticket>>> {
|
||||
self.tickets.get(&id).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Option<Arc<Mutex<Ticket>>>, OverloadedError> {
|
||||
pub fn get(&self, id: TicketId) -> Result<Option<Arc<RwLock<Ticket>>>, 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<Option<Arc<Mutex<Ticket>>>>,
|
||||
response_channel: SyncSender<Option<Arc<RwLock<Ticket>>>>,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -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<TicketId, Arc<Mutex<Ticket>>>,
|
||||
tickets: BTreeMap<TicketId, Arc<RwLock<Ticket>>>,
|
||||
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<Arc<Mutex<Ticket>>> {
|
||||
pub fn get(&self, id: TicketId) -> Option<Arc<RwLock<Ticket>>> {
|
||||
self.tickets.get(&id).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 || {
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
fn intro() -> &'static str {
|
||||
// TODO: fix me 👇
|
||||
"I'm ready to _!"
|
||||
"I'm ready to learn about futures!"
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user