pub struct Post { state: Option>, content: String, } impl Post { pub fn new() -> Post { Post { state: Some(Box::new(Draft {})), content: String::new(), } } pub fn add_text(&mut self, text: &str) { self.content.push_str(text); } pub fn content(&self) -> &str { self.state.as_ref().unwrap().content(self) } pub fn request_review(&mut self) { if let Some(s) = self.state.take() { self.state = Some(s.request_review()) } } pub fn approve(&mut self) { if let Some(s) = self.state.take() { self.state = Some(s.approve()) } } } trait State { fn request_review(self: Box) -> Box; fn approve(self: Box) -> Box; fn reject(self: Box) -> Box; fn content<'a>(&self, _post: &'a Post) -> &'a str { "" } } struct Draft {} impl State for Draft { fn request_review(self: Box) -> Box { Box::new(PendingReview {}) } fn approve(self: Box) -> Box { self } fn reject(self: Box) -> Box { self } } struct PendingReview {} impl State for PendingReview { fn request_review(self: Box) -> Box { self } fn approve(self: Box) -> Box { Box::new(Published {}) } fn reject(self: Box) -> Box { Box::new(Draft {}) } } struct Published {} impl State for Published { fn request_review(self: Box) -> Box { self } fn approve(self: Box) -> Box { self } fn content<'a>(&self, post: &'a Post) -> &'a str { &post.content } fn reject(self: Box) -> Box { self } } fn main() { let mut post = Post::new(); post.add_text("I ate a salad for lunch today"); assert_eq!("", post.content()); post.request_review(); assert_eq!("", post.content()); post.approve(); assert_eq!("I ate a salad for lunch today", post.content()); }