Skip to main content

rs_teststand/license/
license_type.rs

1//! What license the engine is currently running on.
2
3/// The kind of license the engine is using (`Engine.LicenseType`).
4///
5/// Where several are activated on one machine, the engine picks the minimum
6/// that satisfies the request rather than the most capable, so this reports
7/// what is actually in use and not what is installed.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9#[non_exhaustive]
10pub enum LicenseType {
11    /// Full development system.
12    DevelopmentSystem,
13    /// Debug deployment environment.
14    DebugDeploymentEnv,
15    /// Base deployment engine.
16    BaseDeploymentEngine,
17    /// An OEM license.
18    Oem,
19    /// An evaluation license, which expires.
20    Evaluation,
21    /// No license at all.
22    ///
23    /// The state a host has to survive: the engine object may still exist, but
24    /// anything needing a license will refuse.
25    NoLicense,
26    /// A temporary license, taken when the volume license server is
27    /// unreachable. Worth logging: it means the station could not reach the
28    /// server, so it will need to later.
29    Temporary,
30    /// The engine could not determine the type.
31    Other,
32    /// Custom sequence editor deployment.
33    CustomEditorDeployment,
34}
35
36impl LicenseType {
37    /// Maps the engine's number onto a type.
38    ///
39    /// # Errors
40    /// The raw value, when it is one this build does not name. A newer engine
41    /// may define a license type this crate predates, and reporting the number
42    /// is more useful than guessing which existing one it resembles.
43    pub const fn from_bits(bits: i32) -> Result<Self, i32> {
44        match bits {
45            1 => Ok(Self::DevelopmentSystem),
46            2 => Ok(Self::DebugDeploymentEnv),
47            3 => Ok(Self::BaseDeploymentEngine),
48            4 => Ok(Self::Oem),
49            5 => Ok(Self::Evaluation),
50            6 => Ok(Self::NoLicense),
51            7 => Ok(Self::Temporary),
52            8 => Ok(Self::Other),
53            9 => Ok(Self::CustomEditorDeployment),
54            unknown => Err(unknown),
55        }
56    }
57
58    /// The engine's number for this type.
59    #[must_use]
60    pub const fn bits(self) -> i32 {
61        match self {
62            Self::DevelopmentSystem => 1,
63            Self::DebugDeploymentEnv => 2,
64            Self::BaseDeploymentEngine => 3,
65            Self::Oem => 4,
66            Self::Evaluation => 5,
67            Self::NoLicense => 6,
68            Self::Temporary => 7,
69            Self::Other => 8,
70            Self::CustomEditorDeployment => 9,
71        }
72    }
73
74    /// Whether this license lets a host expect to run sequences.
75    ///
76    /// False for [`NoLicense`](Self::NoLicense) only. Everything else grants
77    /// something, though not necessarily everything a caller wants, an
78    /// evaluation license expires and a base deployment engine cannot edit, so
79    /// this is a floor, not a guarantee.
80    #[must_use]
81    pub const fn is_usable(self) -> bool {
82        !matches!(self, Self::NoLicense)
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::LicenseType;
89
90    #[test]
91    fn every_documented_value_round_trips() {
92        for raw in 1..=9 {
93            let parsed = LicenseType::from_bits(raw);
94            assert_eq!(
95                parsed.map(LicenseType::bits),
96                Ok(raw),
97                "{raw} is documented but did not round-trip"
98            );
99        }
100    }
101
102    #[test]
103    fn an_unknown_value_is_returned_rather_than_guessed() {
104        // A newer engine may name a type this build predates. Reporting the
105        // number lets a caller say so; picking a near neighbour would lie.
106        assert_eq!(LicenseType::from_bits(99), Err(99));
107        assert_eq!(LicenseType::from_bits(0), Err(0));
108    }
109
110    #[test]
111    fn only_no_license_is_unusable() {
112        // The distinction a host branches on, so it is pinned.
113        assert!(!LicenseType::NoLicense.is_usable());
114        for usable in [
115            LicenseType::DevelopmentSystem,
116            LicenseType::DebugDeploymentEnv,
117            LicenseType::BaseDeploymentEngine,
118            LicenseType::Oem,
119            LicenseType::Evaluation,
120            LicenseType::Temporary,
121            LicenseType::Other,
122            LicenseType::CustomEditorDeployment,
123        ] {
124            assert!(usable.is_usable(), "{usable:?} should count as usable");
125        }
126    }
127}