You've already forked rust-tutor
generic types, traits and lifetimes
- get claude to create rustlings style exercises based on chapter 10 of the book - update CLAUDE.md to prevent it from producing incorrect exercises - complete exercises/01-generic-cache-system
This commit is contained in:
6
exercises/02-generic-structs/Cargo.toml
Normal file
6
exercises/02-generic-structs/Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "generic_structs"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
15
exercises/02-generic-structs/README.md
Normal file
15
exercises/02-generic-structs/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Generic Message Queue
|
||||
|
||||
Build a message queue system that can handle different types of messages. You'll create generic structs and enums that can queue up emails, notifications, tasks, or any other message type without code duplication.
|
||||
|
||||
## What you'll practice
|
||||
|
||||
- Defining generic structs that hold collections of any type
|
||||
- Creating generic enums for different message states
|
||||
- Writing implementation blocks with generic type parameters
|
||||
- Using associated functions vs instance methods with generics
|
||||
|
||||
## Further information
|
||||
|
||||
- [Generic Data Types](https://doc.rust-lang.org/book/ch10-01-syntax.html)
|
||||
- [Method Definitions](https://doc.rust-lang.org/book/ch05-03-method-syntax.html)
|
||||
102
exercises/02-generic-structs/src/main.rs
Normal file
102
exercises/02-generic-structs/src/main.rs
Normal file
@@ -0,0 +1,102 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
// TODO: Make this struct generic over message type T
|
||||
// It should hold a queue of messages and track total processed count
|
||||
struct MessageQueue {
|
||||
queue: VecDeque<String>,
|
||||
processed_count: usize,
|
||||
}
|
||||
|
||||
// TODO: Make this enum generic over T for message data and E for error data
|
||||
// Messages can be Pending, Processing, or Failed with error info
|
||||
enum MessageStatus {
|
||||
Pending(String),
|
||||
Processing(String),
|
||||
Failed(String, String), // message, error
|
||||
}
|
||||
|
||||
// TODO: Create a generic struct for message metadata
|
||||
// Should store the message of type T and a priority level (u8)
|
||||
struct PriorityMessage {
|
||||
content: String,
|
||||
priority: u8,
|
||||
}
|
||||
|
||||
// TODO: Implement methods for MessageQueue<T>
|
||||
impl MessageQueue<String> {
|
||||
// Create new empty queue
|
||||
fn new() -> Self {
|
||||
todo!("Create new message queue")
|
||||
}
|
||||
|
||||
// Add message to back of queue
|
||||
fn enqueue(&mut self, message: String) {
|
||||
todo!("Add message to queue")
|
||||
}
|
||||
|
||||
// Remove and return next message from front, increment processed count
|
||||
fn dequeue(&mut self) -> Option<String> {
|
||||
todo!("Remove next message")
|
||||
}
|
||||
|
||||
// Get current queue length
|
||||
fn len(&self) -> usize {
|
||||
todo!("Return queue length")
|
||||
}
|
||||
|
||||
// Get total number of processed messages
|
||||
fn total_processed(&self) -> usize {
|
||||
todo!("Return processed count")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_queue_creation() {
|
||||
let queue: MessageQueue<String> = MessageQueue::new();
|
||||
assert_eq!(queue.len(), 0);
|
||||
assert_eq!(queue.total_processed(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enqueue_dequeue() {
|
||||
let mut queue = MessageQueue::new();
|
||||
queue.enqueue("First message".to_string());
|
||||
queue.enqueue("Second message".to_string());
|
||||
|
||||
assert_eq!(queue.len(), 2);
|
||||
assert_eq!(queue.dequeue(), Some("First message".to_string()));
|
||||
assert_eq!(queue.len(), 1);
|
||||
assert_eq!(queue.total_processed(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_message_status_variants() {
|
||||
let pending: MessageStatus<String, String> = MessageStatus::Pending("Task 1".to_string());
|
||||
let failed: MessageStatus<String, String> = MessageStatus::Failed("Task 2".to_string(), "Connection timeout".to_string());
|
||||
|
||||
match pending {
|
||||
MessageStatus::Pending(msg) => assert_eq!(msg, "Task 1"),
|
||||
_ => panic!("Should be Pending"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_priority_message() {
|
||||
let high_priority: PriorityMessage<String> = PriorityMessage {
|
||||
content: "Urgent task".to_string(),
|
||||
priority: 1,
|
||||
};
|
||||
|
||||
let low_priority: PriorityMessage<i32> = PriorityMessage {
|
||||
content: 42,
|
||||
priority: 5,
|
||||
};
|
||||
|
||||
assert_eq!(high_priority.priority, 1);
|
||||
assert_eq!(low_priority.content, 42);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user