ichen_openprotocol/job_card.rs
1use super::TextName;
2use serde::{Deserialize, Serialize};
3use std::convert::TryInto;
4
5/// A data structure containing information on a production job (i.e. a *job card*).
6///
7#[derive(Debug, Eq, PartialEq, Hash, Clone, Serialize, Deserialize)]
8#[serde(rename_all = "camelCase")]
9pub struct JobCard<'a> {
10 /// Unique job ID, which must not be empty or all white-spaces.
11 #[serde(borrow)]
12 job_card_id: TextName<'a>,
13 //
14 /// ID of the set of mold data to load for this job.
15 #[serde(borrow)]
16 mold_id: TextName<'a>,
17 //
18 /// Current production progress, which must not be larger than `total`.
19 progress: u32,
20 //
21 /// Total production count ordered.
22 total: u32,
23}
24
25impl<'a> JobCard<'a> {
26 /// Get the job ID.
27 ///
28 /// # Examples
29 ///
30 /// ~~~
31 /// # use ichen_openprotocol::*;
32 /// # fn main() -> std::result::Result<(), String> {
33 /// let jc = JobCard::try_new("J001", "Mold#001", 100, 1000)?;
34 /// assert_eq!("J001", jc.job_card_id());
35 /// # Ok(())
36 /// # }
37 /// ~~~
38 pub fn job_card_id(&self) -> &str {
39 self.job_card_id.as_ref()
40 }
41
42 /// Get the mold ID.
43 ///
44 /// # Examples
45 ///
46 /// ~~~
47 /// # use ichen_openprotocol::*;
48 /// # fn main() -> std::result::Result<(), String> {
49 /// let jc = JobCard::try_new("J001", "Mold#001", 100, 1000)?;
50 /// assert_eq!("Mold#001", jc.mold_id());
51 /// # Ok(())
52 /// # }
53 /// ~~~
54 pub fn mold_id(&self) -> &str {
55 self.mold_id.as_ref()
56 }
57
58 /// Get the production progress.
59 ///
60 /// # Examples
61 ///
62 /// ~~~
63 /// # use ichen_openprotocol::*;
64 /// # fn main() -> std::result::Result<(), String> {
65 /// let jc = JobCard::try_new("J001", "Mold#001", 100, 1000)?;
66 /// assert_eq!(100, jc.progress());
67 /// # Ok(())
68 /// # }
69 /// ~~~
70 pub fn progress(&self) -> u32 {
71 self.progress
72 }
73
74 /// Get the maximum production order.
75 ///
76 /// # Examples
77 ///
78 /// ~~~
79 /// # use ichen_openprotocol::*;
80 /// # fn main() -> std::result::Result<(), String> {
81 /// let jc = JobCard::try_new("J001", "Mold#001", 100, 1000)?;
82 /// assert_eq!(1000, jc.total());
83 /// # Ok(())
84 /// # }
85 /// ~~~
86 pub fn total(&self) -> u32 {
87 self.total
88 }
89
90 /// Create a new `JobCard` with the specified field values.
91 ///
92 /// # Errors
93 ///
94 /// Returns `Err(String)` is there is an error in the parameters.
95 ///
96 /// ## Error Examples
97 ///
98 /// ~~~
99 /// # use ichen_openprotocol::*;
100 /// assert_eq!(
101 /// Err("invalid value: a non-empty, non-whitespace string required for job card ID".into()),
102 /// JobCard::try_new("", "Mold#001", 0, 10000)
103 /// );
104 ///
105 /// assert_eq!(
106 /// Err("invalid value: a non-empty, non-whitespace string required for mold ID".into()),
107 /// JobCard::try_new("J001", " ", 0, 10000)
108 /// );
109 ///
110 /// assert_eq!(
111 /// Err("progress cannot be larger than total".into()),
112 /// JobCard::try_new("J001", "Mold#001", 1000, 100)
113 /// );
114 /// ~~~
115 ///
116 /// # Examples
117 ///
118 /// ~~~
119 /// # use ichen_openprotocol::*;
120 /// # fn main() -> std::result::Result<(), String> {
121 /// let jobs = vec![
122 /// JobCard::try_new("J001", "Mold#001", 0, 10000)?,
123 /// JobCard::try_new("J002", "Mold#002", 1000, 5000)?,
124 /// JobCard::try_new("J003", "Mold#003", 42, 1000)?,
125 /// JobCard::try_new("J004", "Mold#004", 0, 0)?,
126 /// ];
127 ///
128 /// assert_eq!(4, jobs.len());
129 /// assert_eq!("J002", jobs[1].job_card_id());
130 /// assert_eq!(1000, jobs[2].total());
131 /// # Ok(())
132 /// # }
133 /// ~~~
134 pub fn try_new(
135 id: &'a str,
136 mold: &'a str,
137 progress: u32,
138 total: u32,
139 ) -> std::result::Result<Self, String> {
140 if progress > total {
141 return Err("progress cannot be larger than total".into());
142 }
143
144 Ok(Self {
145 job_card_id: id.try_into().map_err(|e| format!("{} for job card ID", e))?,
146 mold_id: mold.try_into().map_err(|e| format!("{} for mold ID", e))?,
147 progress,
148 total,
149 })
150 }
151}