Update blog example to use types to enforce state
This commit is contained in:
parent
48e6aba776
commit
36ed658b19
73
.idea/workspace.xml
generated
73
.idea/workspace.xml
generated
@ -2,9 +2,8 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="c8f42924-1cd2-4b1c-bcff-602a3368bb16" name="Default Changelist" comment="">
|
<list default="true" id="c8f42924-1cd2-4b1c-bcff-602a3368bb16" name="Default Changelist" comment="">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/blog/src/lib.rs" beforeDir="false" afterPath="$PROJECT_DIR$/blog/src/lib.rs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/rust.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/rust.iml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/blog/src/main.rs" beforeDir="false" afterPath="$PROJECT_DIR$/blog/src/main.rs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
@ -17,8 +16,8 @@
|
|||||||
<file pinned="false" current-in-tab="true">
|
<file pinned="false" current-in-tab="true">
|
||||||
<entry file="file://$PROJECT_DIR$/blog/src/main.rs">
|
<entry file="file://$PROJECT_DIR$/blog/src/main.rs">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="224">
|
<state relative-caret-position="176">
|
||||||
<caret line="14" lean-forward="true" selection-start-line="14" selection-end-line="14" />
|
<caret line="11" column="64" selection-start-line="11" selection-start-column="64" selection-end-line="11" selection-end-column="64" />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
@ -26,29 +25,13 @@
|
|||||||
<file pinned="false" current-in-tab="false">
|
<file pinned="false" current-in-tab="false">
|
||||||
<entry file="file://$PROJECT_DIR$/blog/src/lib.rs">
|
<entry file="file://$PROJECT_DIR$/blog/src/lib.rs">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="624">
|
<state relative-caret-position="672">
|
||||||
<caret line="39" column="5" lean-forward="true" selection-start-line="39" selection-start-column="5" selection-end-line="39" selection-end-column="5" />
|
<caret line="42" column="1" lean-forward="true" selection-start-line="42" selection-start-column="1" selection-end-line="42" selection-end-column="1" />
|
||||||
<folding>
|
<folding>
|
||||||
<element signature="e#276#277#0" expanded="true" />
|
<element signature="e#240#241#0" expanded="true" />
|
||||||
<element signature="e#303#304#0" expanded="true" />
|
<element signature="e#268#269#0" expanded="true" />
|
||||||
<element signature="e#352#353#0" expanded="true" />
|
<element signature="e#656#657#0" expanded="true" />
|
||||||
<element signature="e#377#378#0" expanded="true" />
|
<element signature="e#699#700#0" expanded="true" />
|
||||||
<element signature="e#879#880#0" expanded="true" />
|
|
||||||
<element signature="e#896#897#0" expanded="true" />
|
|
||||||
<element signature="e#701#702#0" expanded="true" />
|
|
||||||
<element signature="e#726#727#0" expanded="true" />
|
|
||||||
<element signature="e#983#984#0" expanded="true" />
|
|
||||||
<element signature="e#1002#1003#0" expanded="true" />
|
|
||||||
<element signature="e#856#857#0" expanded="true" />
|
|
||||||
<element signature="e#875#876#0" expanded="true" />
|
|
||||||
<element signature="e#1196#1197#0" expanded="true" />
|
|
||||||
<element signature="e#1221#1222#0" expanded="true" />
|
|
||||||
<element signature="e#1347#1348#0" expanded="true" />
|
|
||||||
<element signature="e#1366#1367#0" expanded="true" />
|
|
||||||
<element signature="e#1423#1424#0" expanded="true" />
|
|
||||||
<element signature="e#1442#1443#0" expanded="true" />
|
|
||||||
<element signature="e#1599#1600#0" expanded="true" />
|
|
||||||
<element signature="e#1615#1616#0" expanded="true" />
|
|
||||||
</folding>
|
</folding>
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
@ -132,8 +115,8 @@
|
|||||||
<option value="$PROJECT_DIR$/trait_objects/Cargo.toml" />
|
<option value="$PROJECT_DIR$/trait_objects/Cargo.toml" />
|
||||||
<option value="$PROJECT_DIR$/gui/src/main.rs" />
|
<option value="$PROJECT_DIR$/gui/src/main.rs" />
|
||||||
<option value="$PROJECT_DIR$/gui/src/lib.rs" />
|
<option value="$PROJECT_DIR$/gui/src/lib.rs" />
|
||||||
<option value="$PROJECT_DIR$/blog/src/main.rs" />
|
|
||||||
<option value="$PROJECT_DIR$/blog/src/lib.rs" />
|
<option value="$PROJECT_DIR$/blog/src/lib.rs" />
|
||||||
|
<option value="$PROJECT_DIR$/blog/src/main.rs" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
@ -217,7 +200,7 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent">
|
<component name="PropertiesComponent">
|
||||||
<property name="JavaScriptWeakerCompletionTypeGuess" value="true" />
|
<property name="JavaScriptWeakerCompletionTypeGuess" value="true" />
|
||||||
<property name="com.android.tools.idea.instantapp.provision.ProvisionBeforeRunTaskProvider.myTimeStamp" value="1549482664512" />
|
<property name="com.android.tools.idea.instantapp.provision.ProvisionBeforeRunTaskProvider.myTimeStamp" value="1549483257467" />
|
||||||
<property name="javascript.nodejs.core.library.configured.version" value="7.1.0" />
|
<property name="javascript.nodejs.core.library.configured.version" value="7.1.0" />
|
||||||
<property name="js.eslint.eslintPackage" value="$USER_HOME$/.yarn-config/global/node_modules/.bin/eslint" />
|
<property name="js.eslint.eslintPackage" value="$USER_HOME$/.yarn-config/global/node_modules/.bin/eslint" />
|
||||||
<property name="js.eslint.nodeInterpreter" value="project" />
|
<property name="js.eslint.nodeInterpreter" value="project" />
|
||||||
@ -822,37 +805,21 @@
|
|||||||
</entry>
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/blog/src/lib.rs">
|
<entry file="file://$PROJECT_DIR$/blog/src/lib.rs">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="624">
|
<state relative-caret-position="672">
|
||||||
<caret line="39" column="5" lean-forward="true" selection-start-line="39" selection-start-column="5" selection-end-line="39" selection-end-column="5" />
|
<caret line="42" column="1" lean-forward="true" selection-start-line="42" selection-start-column="1" selection-end-line="42" selection-end-column="1" />
|
||||||
<folding>
|
<folding>
|
||||||
<element signature="e#276#277#0" expanded="true" />
|
<element signature="e#240#241#0" expanded="true" />
|
||||||
<element signature="e#303#304#0" expanded="true" />
|
<element signature="e#268#269#0" expanded="true" />
|
||||||
<element signature="e#352#353#0" expanded="true" />
|
<element signature="e#656#657#0" expanded="true" />
|
||||||
<element signature="e#377#378#0" expanded="true" />
|
<element signature="e#699#700#0" expanded="true" />
|
||||||
<element signature="e#879#880#0" expanded="true" />
|
|
||||||
<element signature="e#896#897#0" expanded="true" />
|
|
||||||
<element signature="e#701#702#0" expanded="true" />
|
|
||||||
<element signature="e#726#727#0" expanded="true" />
|
|
||||||
<element signature="e#983#984#0" expanded="true" />
|
|
||||||
<element signature="e#1002#1003#0" expanded="true" />
|
|
||||||
<element signature="e#856#857#0" expanded="true" />
|
|
||||||
<element signature="e#875#876#0" expanded="true" />
|
|
||||||
<element signature="e#1196#1197#0" expanded="true" />
|
|
||||||
<element signature="e#1221#1222#0" expanded="true" />
|
|
||||||
<element signature="e#1347#1348#0" expanded="true" />
|
|
||||||
<element signature="e#1366#1367#0" expanded="true" />
|
|
||||||
<element signature="e#1423#1424#0" expanded="true" />
|
|
||||||
<element signature="e#1442#1443#0" expanded="true" />
|
|
||||||
<element signature="e#1599#1600#0" expanded="true" />
|
|
||||||
<element signature="e#1615#1616#0" expanded="true" />
|
|
||||||
</folding>
|
</folding>
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/blog/src/main.rs">
|
<entry file="file://$PROJECT_DIR$/blog/src/main.rs">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="224">
|
<state relative-caret-position="176">
|
||||||
<caret line="14" lean-forward="true" selection-start-line="14" selection-end-line="14" />
|
<caret line="11" column="64" selection-start-line="11" selection-start-column="64" selection-end-line="11" selection-end-column="64" />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "blog"
|
name = "blog"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
authors = ["Timothy Warren <twarren@nabancard.com>"]
|
authors = ["Timothy Warren <twarren@nabancard.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
@ -1,81 +1,44 @@
|
|||||||
pub struct Post {
|
pub struct Post {
|
||||||
state: Option<Box<dyn State>>,
|
content: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DraftPost {
|
||||||
content: String,
|
content: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Post {
|
impl Post {
|
||||||
pub fn new() -> Post {
|
pub fn new() -> DraftPost {
|
||||||
Post {
|
DraftPost {
|
||||||
state: Some(Box::new(Draft {})),
|
|
||||||
content: String::new(),
|
content: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn content(&self) -> &str {
|
||||||
|
&self.content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DraftPost {
|
||||||
pub fn add_text(&mut self, text: &str) {
|
pub fn add_text(&mut self, text: &str) {
|
||||||
self.content.push_str(text);
|
self.content.push_str(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content(&self) -> &str {
|
pub fn request_review(self) -> PendingReviewPost {
|
||||||
self.state.as_ref().unwrap().content(&self)
|
PendingReviewPost {
|
||||||
}
|
content: self.content,
|
||||||
|
|
||||||
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 {
|
pub struct PendingReviewPost {
|
||||||
fn request_review(self: Box<Self>) -> Box<dyn State>;
|
content: String,
|
||||||
fn approve(self: Box<Self>) -> Box<dyn State>;
|
}
|
||||||
fn content<'a>(&self, post: &'a Post) -> &'a str {
|
|
||||||
""
|
impl PendingReviewPost {
|
||||||
|
pub fn approve(self) -> Post {
|
||||||
|
Post {
|
||||||
|
content: self.content,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Draft {}
|
|
||||||
|
|
||||||
impl State for Draft {
|
|
||||||
fn request_review(self: Box<Self>) -> Box<dyn State> {
|
|
||||||
Box::new(PendingReview {})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn approve(self: Box<Self>) -> Box<dyn State> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PendingReview {}
|
|
||||||
|
|
||||||
impl State for PendingReview {
|
|
||||||
fn request_review(self: Box<Self>) -> Box<dyn State> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn approve(self: Box<Self>) -> Box<dyn State> {
|
|
||||||
Box::new(Published {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Published {}
|
|
||||||
|
|
||||||
impl State for Published {
|
|
||||||
fn request_review(self: Box<Self>) -> Box<dyn State> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn approve(self: Box<Self>) -> Box<dyn State> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn content<'a>(&self, post: &'a Post) -> &'a str {
|
|
||||||
&post.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -4,11 +4,10 @@ fn main() {
|
|||||||
let mut post = Post::new();
|
let mut post = Post::new();
|
||||||
|
|
||||||
post.add_text("I ate a salad for lunch today");
|
post.add_text("I ate a salad for lunch today");
|
||||||
assert_eq!("", post.content());
|
|
||||||
|
|
||||||
post.request_review();
|
let post = post.request_review();
|
||||||
assert_eq!("", post.content());
|
|
||||||
|
let post = post.approve();
|
||||||
|
|
||||||
post.approve();
|
|
||||||
assert_eq!("I ate a salad for lunch today", post.content());
|
assert_eq!("I ate a salad for lunch today", post.content());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user