Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 77 additions & 1 deletion 2_idioms/2_1_type_safety/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,79 @@
use crate::post::{New, Post, PostData};

fn main() {
println!("Implement me!");
let post = Post::<New>::new(PostData::default());

// post.allow(); error
post.publish().allow().delete();

let post = Post::<New>::new(PostData::default());
post.publish().deny();
}

mod post {
use std::marker::PhantomData;

pub struct New;
pub struct Unmoderated;
pub struct Published;
pub struct Deleted;

#[derive(Default)]
pub struct PostData {
id: u64,
user_id: u64,
title: String,
body: String,
}

#[derive(Clone)]
pub struct Post<State> {
id: u64,
user_id: u64,
title: String,
body: String,
_marker: PhantomData<State>,
}
impl<State> Post<State> {
pub fn new(data: PostData) -> Post<New> {
Post {
id: data.id,
user_id: data.user_id,
title: data.title,
body: data.body,
_marker: PhantomData,
}
}
}
impl Post<New> {
pub fn publish(self) -> Post<Unmoderated> {
self.transition::<Unmoderated>()
}
}
impl Post<Unmoderated> {
pub fn allow(self) -> Post<Published> {
self.transition::<Published>()
}

pub fn deny(self) -> Post<Deleted> {
self.transition::<Deleted>()
}
}
impl Post<Published> {
pub fn delete(self) -> Post<Deleted> {
self.transition::<Deleted>()
}
}

impl<State> Post<State> {
pub fn transition<NextState>(self) -> Post<NextState> {
Post {
id: self.id,
user_id: self.user_id,
title: self.title,
body: self.body,
_marker: PhantomData,
}
}
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Each step must be performed as a separate [PR (pull request)][PR] with an approp
- [ ] [1.8. Thread safety][Step 1.8] (1 day)
- [ ] [1.9. Phantom types][Step 1.9] (1 day)
- [ ] [2. Idioms][Step 2] (2 days, after all sub-steps)
- [ ] [2.1. Rich types ensure correctness][Step 2.1] (1 day)
- [x] [2.1. Rich types ensure correctness][Step 2.1] (1 day)
- [ ] [2.2. Swapping values with `mem::replace`][Step 2.2] (1 day)
- [ ] [2.3. Bound behavior, not data][Step 2.3] (1 day)
- [ ] [2.4. Abstract type in, concrete type out][Step 2.4] (1 day)
Expand Down