Compare commits

..

4 Commits

Author SHA1 Message Date
b044878fe8 complete chapter 7
Some checks failed
CI / gravity (push) Has been skipped
CI / build (push) Failing after 14s
CI / is_fresh (push) Successful in 49s
CI / formatter (push) Failing after 17s
2025-05-02 14:11:16 +05:30
4fbee2d894 complete threads till 06 2025-04-15 16:25:01 +05:30
9bc063a05b completed 06 ticket management
Some checks failed
CI / build (push) Failing after 1m16s
CI / gravity (push) Has been skipped
CI / is_fresh (push) Successful in 26s
CI / formatter (push) Failing after 17s
2025-04-07 12:12:47 +05:30
199b57aad8 completed till 11 2025-04-02 17:54:30 +05:30
29 changed files with 245 additions and 64 deletions

1
Cargo.lock generated
View File

@@ -205,6 +205,7 @@ dependencies = [
name = "bounded" name = "bounded"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"thiserror",
"ticket_fields", "ticket_fields",
] ]

View File

@@ -7,6 +7,14 @@ pub struct TicketStore {
tickets: Vec<Ticket>, tickets: Vec<Ticket>,
} }
impl TicketStore {
fn in_progress(&self) -> impl Iterator<Item = &Ticket> {
self.tickets
.iter()
.filter(|&a| a.status == Status::InProgress)
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Ticket { pub struct Ticket {
pub title: TicketTitle, pub title: TicketTitle,

View File

@@ -33,7 +33,10 @@ impl TicketStore {
// that can be infallibly converted into a `Ticket`. // that can be infallibly converted into a `Ticket`.
// This can make it nicer to use the method, as it removes the syntax noise of `.into()` // This can make it nicer to use the method, as it removes the syntax noise of `.into()`
// from the calling site. It can worsen the quality of the compiler error messages, though. // from the calling site. It can worsen the quality of the compiler error messages, though.
pub fn add_ticket(&mut self, ticket: impl Into<Ticket>) { pub fn add_ticket<T>(&mut self, ticket: T)
where
T: Into<Ticket>,
{
self.tickets.push(ticket.into()); self.tickets.push(ticket.into());
} }
} }

View File

@@ -1,6 +1,9 @@
// TODO: Define a function named `sum` that takes a reference to a slice of `u32` and returns the sum of all // TODO: Define a function named `sum` that takes a reference to a slice of `u32` and returns the sum of all
// elements in the slice. // elements in the slice.
fn sum(v: &[u32]) -> u32 {
v.iter().sum()
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@@ -1,6 +1,14 @@
// TODO: Define a function named `squared` that raises all `i32`s within a slice to the power of 2. // TODO: Define a function named `squared` that raises all `i32`s within a slice to the power of 2.
// The slice should be modified in place. // The slice should be modified in place.
fn squared(v: &mut [i32]) {
for val in v.iter_mut() {
*val = val.pow(2);
}
// let b = v.iter().map(|a| a.pow(2)).collect::<Vec<_>>().as_slice();
// v = b;
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@@ -11,6 +11,7 @@ use ticket_fields::{TicketDescription, TicketTitle};
#[derive(Clone)] #[derive(Clone)]
pub struct TicketStore { pub struct TicketStore {
tickets: Vec<Ticket>, tickets: Vec<Ticket>,
total: usize,
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
@@ -41,11 +42,25 @@ impl TicketStore {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tickets: Vec::new(), tickets: Vec::new(),
total: 0,
} }
} }
pub fn add_ticket(&mut self, ticket: Ticket) { pub fn add_ticket(&mut self, ticket: TicketDraft) -> TicketId {
self.tickets.push(ticket); let newID = TicketId(self.total as u64 + 1);
let tick: Ticket = Ticket {
title: ticket.title,
description: ticket.description,
status: Status::ToDo,
id: newID,
};
self.tickets.push(tick);
self.total += 1;
return newID;
}
pub fn get(&self, id: TicketId) -> Option<&Ticket> {
return Some(&self.tickets[(id.0 - 1) as usize]);
} }
} }

View File

@@ -1,5 +1,7 @@
// TODO: Implement `Index<&TicketId>` and `Index<TicketId>` for `TicketStore`. // TODO: Implement `Index<&TicketId>` and `Index<TicketId>` for `TicketStore`.
use std::ops::Index;
use ticket_fields::{TicketDescription, TicketTitle}; use ticket_fields::{TicketDescription, TicketTitle};
#[derive(Clone)] #[derive(Clone)]
@@ -58,6 +60,20 @@ impl TicketStore {
} }
} }
impl Index<TicketId> for TicketStore {
type Output = Ticket;
fn index(&self, index: TicketId) -> &Self::Output {
return &self.tickets[index.0 as usize];
}
}
impl Index<&TicketId> for TicketStore {
type Output = Ticket;
fn index(&self, index: &TicketId) -> &Self::Output {
return &self.tickets[index.0 as usize];
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{Status, TicketDraft, TicketStore}; use crate::{Status, TicketDraft, TicketStore};

View File

@@ -1,6 +1,6 @@
// TODO: Implement `IndexMut<&TicketId>` and `IndexMut<TicketId>` for `TicketStore`. // TODO: Implement `IndexMut<&TicketId>` and `IndexMut<TicketId>` for `TicketStore`.
use std::ops::Index; use std::ops::{Index, IndexMut};
use ticket_fields::{TicketDescription, TicketTitle}; use ticket_fields::{TicketDescription, TicketTitle};
#[derive(Clone)] #[derive(Clone)]
@@ -75,6 +75,18 @@ impl Index<&TicketId> for TicketStore {
} }
} }
impl IndexMut<TicketId> for TicketStore {
fn index_mut(&mut self, index: TicketId) -> &mut Self::Output {
self.tickets.iter_mut().find(|a| a.id == index).unwrap()
}
}
impl IndexMut<&TicketId> for TicketStore {
fn index_mut(&mut self, index: &TicketId) -> &mut Self::Output {
self.tickets.iter_mut().find(|a| a.id == *index).unwrap()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{Status, TicketDraft, TicketStore}; use crate::{Status, TicketDraft, TicketStore};

View File

@@ -11,7 +11,7 @@ pub struct TicketStore {
counter: u64, counter: u64,
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct TicketId(u64); pub struct TicketId(u64);
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@@ -38,7 +38,7 @@ pub enum Status {
impl TicketStore { impl TicketStore {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tickets: todo!(), tickets: HashMap::new(),
counter: 0, counter: 0,
} }
} }
@@ -52,16 +52,16 @@ impl TicketStore {
description: ticket.description, description: ticket.description,
status: Status::ToDo, status: Status::ToDo,
}; };
todo!(); self.tickets.insert(id, ticket);
id id
} }
pub fn get(&self, id: TicketId) -> Option<&Ticket> { pub fn get(&self, id: TicketId) -> Option<&Ticket> {
todo!() self.tickets.get(&id)
} }
pub fn get_mut(&mut self, id: TicketId) -> Option<&mut Ticket> { pub fn get_mut(&mut self, id: TicketId) -> Option<&mut Ticket> {
todo!() self.tickets.get_mut(&id)
} }
} }

View File

@@ -13,7 +13,16 @@ pub struct TicketStore {
counter: u64, counter: u64,
} }
#[derive(Clone, Copy, Debug, PartialEq)] impl<'a> IntoIterator for &'a TicketStore {
type Item = &'a Ticket;
type IntoIter = std::collections::btree_map::Values<'a, TicketId, Ticket>;
fn into_iter(self) -> Self::IntoIter {
self.tickets.values()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
pub struct TicketId(u64); pub struct TicketId(u64);
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@@ -40,7 +49,7 @@ pub enum Status {
impl TicketStore { impl TicketStore {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
tickets: todo!(), tickets: BTreeMap::new(),
counter: 0, counter: 0,
} }
} }
@@ -54,16 +63,16 @@ impl TicketStore {
description: ticket.description, description: ticket.description,
status: Status::ToDo, status: Status::ToDo,
}; };
todo!(); self.tickets.insert(id, ticket);
id id
} }
pub fn get(&self, id: TicketId) -> Option<&Ticket> { pub fn get(&self, id: TicketId) -> Option<&Ticket> {
todo!() self.tickets.get(&id)
} }
pub fn get_mut(&mut self, id: TicketId) -> Option<&mut Ticket> { pub fn get_mut(&mut self, id: TicketId) -> Option<&mut Ticket> {
todo!() self.tickets.get_mut(&id)
} }
} }

View File

@@ -1,6 +1,6 @@
fn intro() -> &'static str { fn intro() -> &'static str {
// TODO: fix me 👇 // TODO: fix me 👇
"I'm ready to _!" "I'm ready to build a concurrent ticket management system!"
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -15,7 +15,14 @@
use std::thread; use std::thread;
pub fn sum(v: Vec<i32>) -> i32 { pub fn sum(v: Vec<i32>) -> i32 {
todo!() // let mut c1 = (v.clone()[..v.len() / 2]).iter().collect::<Vec<_>>();
// let mut c2 = (v.clone()[v.len() / 2..]).iter().collect::<Vec<_>>();
let (c1, c2) = v.split_at(v.len() / 2);
let c1 = c1.to_vec();
let c2 = c2.to_vec();
let t1 = std::thread::spawn(move || c1.iter().sum::<i32>());
let t2 = std::thread::spawn(move || c2.iter().sum::<i32>());
t1.join().unwrap() + t2.join().unwrap()
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -4,7 +4,10 @@
use std::thread; use std::thread;
pub fn sum(slice: &'static [i32]) -> i32 { pub fn sum(slice: &'static [i32]) -> i32 {
todo!() let (s1, s2) = slice.split_at(slice.len() / 2);
let t1 = std::thread::spawn(|| s1.iter().sum::<i32>());
let t2 = std::thread::spawn(|| s2.iter().sum::<i32>());
t1.join().unwrap() + t2.join().unwrap()
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -6,7 +6,11 @@
use std::thread; use std::thread;
pub fn sum(v: Vec<i32>) -> i32 { pub fn sum(v: Vec<i32>) -> i32 {
todo!() let lv = v.leak();
let (s1, s2) = lv.split_at(lv.len() / 2);
let t1 = std::thread::spawn(|| s1.iter().sum::<i32>());
let t2 = std::thread::spawn(|| s2.iter().sum::<i32>());
return t1.join().unwrap() + t2.join().unwrap();
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -3,7 +3,13 @@
// Don't perform any heap allocation. Don't leak any memory. // Don't perform any heap allocation. Don't leak any memory.
pub fn sum(v: Vec<i32>) -> i32 { pub fn sum(v: Vec<i32>) -> i32 {
todo!() let mid = v.len() / 2;
let (s1, s2) = v.split_at(mid);
std::thread::scope(|scope| {
let t1 = scope.spawn(|| s1.iter().sum::<i32>());
let t2 = scope.spawn(|| s2.iter().sum::<i32>());
t1.join().unwrap() + t2.join().unwrap()
})
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -1,10 +1,13 @@
use std::sync::mpsc::{Receiver, Sender}; use std::sync::mpsc::{Receiver, Sender};
use data::TicketDraft;
use store::TicketStore;
pub mod data; pub mod data;
pub mod store; pub mod store;
pub enum Command { pub enum Command {
Insert(todo!()), Insert(TicketDraft),
} }
// Start the system by spawning the server thread. // Start the system by spawning the server thread.
@@ -20,4 +23,14 @@ pub fn launch() -> Sender<Command> {
// Enter a loop: wait for a command to show up in // Enter a loop: wait for a command to show up in
// the channel, then execute it, then start waiting // the channel, then execute it, then start waiting
// for the next command. // for the next command.
pub fn server(receiver: Receiver<Command>) {} pub fn server(receiver: Receiver<Command>) {
let mut tickStor = TicketStore::new();
'aLoop: loop {
let command = receiver.recv().ok().unwrap();
match command {
Command::Insert(a) => {
tickStor.add_ticket(a);
}
}
}
}

View File

@@ -26,7 +26,7 @@ fn ready() {
// since our server doesn't expose any **read** actions. // since our server doesn't expose any **read** actions.
// We have no way to know if the inserts are actually happening and if they // We have no way to know if the inserts are actually happening and if they
// are happening correctly. // are happening correctly.
let move_forward = false; let move_forward = true;
assert!(move_forward); assert!(move_forward);
} }

View File

@@ -6,18 +6,18 @@ use std::rc::Rc;
pub struct DropTracker<T> { pub struct DropTracker<T> {
value: T, value: T,
counter: todo!(), counter: Rc<RefCell<usize>>,
} }
impl<T> DropTracker<T> { impl<T> DropTracker<T> {
pub fn new(value: T, counter: todo!()) -> Self { pub fn new(value: T, counter: Rc<RefCell<usize>>) -> Self {
Self { value, counter } Self { value, counter }
} }
} }
impl<T> Drop for DropTracker<T> { impl<T> Drop for DropTracker<T> {
fn drop(&mut self) { fn drop(&mut self) {
todo!() *self.counter.borrow_mut() += 1;
} }
} }

View File

@@ -1,4 +1,7 @@
use data::{Ticket, TicketDraft};
use std::sync::mpsc::{Receiver, Sender}; use std::sync::mpsc::{Receiver, Sender};
use store::TicketId;
use crate::store::TicketStore; use crate::store::TicketStore;
pub mod data; pub mod data;
@@ -6,8 +9,14 @@ pub mod store;
// Refer to the tests to understand the expected schema. // Refer to the tests to understand the expected schema.
pub enum Command { pub enum Command {
Insert { todo!() }, Insert {
Get { todo!() } draft: TicketDraft,
response_sender: Sender<TicketId>,
},
Get {
id: TicketId,
response_sender: Sender<Option<Ticket>>,
},
} }
pub fn launch() -> Sender<Command> { pub fn launch() -> Sender<Command> {
@@ -21,19 +30,25 @@ pub fn server(receiver: Receiver<Command>) {
let mut store = TicketStore::new(); let mut store = TicketStore::new();
loop { loop {
match receiver.recv() { match receiver.recv() {
Ok(Command::Insert {}) => { Ok(Command::Insert {
todo!() draft,
response_sender,
}) => {
let id = store.add_ticket(draft);
response_sender.send(id);
} }
Ok(Command::Get { Ok(Command::Get {
todo!() id,
response_sender,
}) => { }) => {
todo!() let tick = store.get(id);
response_sender.send(tick.cloned());
} }
Err(_) => { Err(_) => {
// There are no more senders, so we can safely break // There are no more senders, so we can safely break
// and shut down the server. // and shut down the server.
break break;
}, }
} }
} }
} }

View File

@@ -7,23 +7,38 @@ pub mod store;
#[derive(Clone)] #[derive(Clone)]
// TODO: flesh out the client implementation. // TODO: flesh out the client implementation.
pub struct TicketStoreClient {} pub struct TicketStoreClient {
sender: Sender<Command>,
}
impl TicketStoreClient { impl TicketStoreClient {
// Feel free to panic on all errors, for simplicity. // Feel free to panic on all errors, for simplicity.
pub fn insert(&self, draft: TicketDraft) -> TicketId { 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> { 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 { pub fn launch() -> TicketStoreClient {
let (sender, receiver) = std::sync::mpsc::channel(); let (sender, receiver) = std::sync::mpsc::channel();
std::thread::spawn(move || server(receiver)); std::thread::spawn(move || server(receiver));
todo!() TicketStoreClient { sender }
} }
// No longer public! This becomes an internal detail of the library now. // No longer public! This becomes an internal detail of the library now.

View File

@@ -5,3 +5,4 @@ edition = "2021"
[dependencies] [dependencies]
ticket_fields = { path = "../../../helpers/ticket_fields" } ticket_fields = { path = "../../../helpers/ticket_fields" }
thiserror="* "

View File

@@ -1,40 +1,58 @@
// TODO: Convert the implementation to use bounded channels. // TODO: Convert the implementation to use bounded channels.
use crate::data::{Ticket, TicketDraft}; use crate::data::{Ticket, TicketDraft};
use crate::store::{TicketId, TicketStore}; use crate::store::{TicketId, TicketStore};
use std::sync::mpsc::{Receiver, Sender}; use std::sync::mpsc::{Receiver, Sender, SyncSender};
pub mod data; pub mod data;
pub mod store; pub mod store;
#[derive(Clone)] #[derive(Clone)]
pub struct TicketStoreClient { pub struct TicketStoreClient {
sender: todo!(), sender: SyncSender<Command>,
} }
#[derive(Debug, thiserror::Error)]
#[error("Server is overloaded")]
pub struct OverLoadedError;
impl TicketStoreClient { impl TicketStoreClient {
pub fn insert(&self, draft: TicketDraft) -> Result<TicketId, todo!()> { pub fn insert(&self, draft: TicketDraft) -> Result<TicketId, OverLoadedError> {
todo!() 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!()> { pub fn get(&self, id: TicketId) -> Result<Option<Ticket>, OverLoadedError> {
todo!() 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 { pub fn launch(capacity: usize) -> TicketStoreClient {
todo!(); let (sender, receiver) = std::sync::mpsc::sync_channel(capacity);
std::thread::spawn(move || server(receiver)); std::thread::spawn(move || server(receiver));
todo!() TicketStoreClient { sender }
} }
enum Command { enum Command {
Insert { Insert {
draft: TicketDraft, draft: TicketDraft,
response_channel: todo!(), response_channel: SyncSender<TicketId>,
}, },
Get { Get {
id: TicketId, id: TicketId,
response_channel: todo!(), response_channel: SyncSender<Option<Ticket>>,
}, },
} }
@@ -47,14 +65,14 @@ pub fn server(receiver: Receiver<Command>) {
response_channel, response_channel,
}) => { }) => {
let id = store.add_ticket(draft); let id = store.add_ticket(draft);
todo!() response_channel.send(id);
} }
Ok(Command::Get { Ok(Command::Get {
id, id,
response_channel, response_channel,
}) => { }) => {
let ticket = store.get(id); let ticket = store.get(id);
todo!() response_channel.send(ticket.cloned());
} }
Err(_) => { Err(_) => {
// There are no more senders, so we can safely break // There are no more senders, so we can safely break

View File

@@ -35,7 +35,15 @@ impl TicketStoreClient {
Ok(response_receiver.recv().unwrap()) 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)] #[derive(Debug, thiserror::Error)]
@@ -85,7 +93,23 @@ pub fn server(receiver: Receiver<Command>) {
patch, patch,
response_channel, 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(_) => { Err(_) => {
// There are no more senders, so we can safely break // There are no more senders, so we can safely break

View File

@@ -28,13 +28,13 @@ impl TicketStore {
description: ticket.description, description: ticket.description,
status: Status::ToDo, status: Status::ToDo,
}; };
todo!(); self.tickets.insert(id, Arc::new(Mutex::new(ticket)));
id id
} }
// The `get` method should return a handle to the ticket // The `get` method should return a handle to the ticket
// which allows the caller to either read or modify 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<Arc<Mutex<Ticket>>> {
todo!() self.tickets.get(&id).cloned()
} }
} }

View File

@@ -1,7 +1,7 @@
// TODO: Replace `Mutex` with `RwLock` in the `TicketStore` struct and // TODO: Replace `Mutex` with `RwLock` in the `TicketStore` struct and
// all other relevant places to allow multiple readers to access the ticket store concurrently. // 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::mpsc::{sync_channel, Receiver, SyncSender, TrySendError};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex, RwLock};
use crate::data::{Ticket, TicketDraft}; use crate::data::{Ticket, TicketDraft};
use crate::store::{TicketId, TicketStore}; use crate::store::{TicketId, TicketStore};
@@ -26,7 +26,7 @@ impl TicketStoreClient {
Ok(response_receiver.recv().unwrap()) 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); let (response_sender, response_receiver) = sync_channel(1);
self.sender self.sender
.try_send(Command::Get { .try_send(Command::Get {
@@ -55,7 +55,7 @@ enum Command {
}, },
Get { Get {
id: TicketId, id: TicketId,
response_channel: SyncSender<Option<Arc<Mutex<Ticket>>>>, response_channel: SyncSender<Option<Arc<RwLock<Ticket>>>>,
}, },
} }

View File

@@ -1,13 +1,13 @@
use crate::data::{Status, Ticket, TicketDraft}; use crate::data::{Status, Ticket, TicketDraft};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex, RwLock};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct TicketId(u64); pub struct TicketId(u64);
#[derive(Clone)] #[derive(Clone)]
pub struct TicketStore { pub struct TicketStore {
tickets: BTreeMap<TicketId, Arc<Mutex<Ticket>>>, tickets: BTreeMap<TicketId, Arc<RwLock<Ticket>>>,
counter: u64, counter: u64,
} }
@@ -28,14 +28,14 @@ impl TicketStore {
description: ticket.description, description: ticket.description,
status: Status::ToDo, status: Status::ToDo,
}; };
let ticket = Arc::new(Mutex::new(ticket)); let ticket = Arc::new(RwLock::new(ticket));
self.tickets.insert(id, ticket); self.tickets.insert(id, ticket);
id id
} }
// The `get` method should return a handle to the ticket // The `get` method should return a handle to the ticket
// which allows the caller to either read or modify 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() self.tickets.get(&id).cloned()
} }
} }

View File

@@ -7,7 +7,7 @@ use without_channels::store::TicketStore;
#[test] #[test]
fn works() { fn works() {
let store = todo!(); let store = Arc::new(RwLock::new(TicketStore::new()));
let store1 = store.clone(); let store1 = store.clone();
let client1 = spawn(move || { let client1 = spawn(move || {

View File

@@ -1,6 +1,6 @@
// Not much to be exercised on `Sync`, just a thing to remember. // Not much to be exercised on `Sync`, just a thing to remember.
fn outro() -> &'static str { fn outro() -> &'static str {
"I have a good understanding of __!" "I have a good understanding of Send and Sync!"
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -1,6 +1,6 @@
fn intro() -> &'static str { fn intro() -> &'static str {
// TODO: fix me 👇 // TODO: fix me 👇
"I'm ready to _!" "I'm ready to learn about futures!"
} }
#[cfg(test)] #[cfg(test)]