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}