service_manager/
typed.rs

1use super::{
2    LaunchdServiceManager, OpenRcServiceManager, RcdServiceManager, ScServiceManager,
3    ServiceInstallCtx, ServiceLevel, ServiceManager, ServiceManagerKind, ServiceStartCtx,
4    ServiceStopCtx, ServiceUninstallCtx, SystemdServiceManager, WinSwServiceManager,
5};
6use std::io;
7
8/// Represents an implementation of a known [`ServiceManager`]
9#[derive(Clone, Debug, PartialEq, Eq)]
10pub enum TypedServiceManager {
11    Launchd(LaunchdServiceManager),
12    OpenRc(OpenRcServiceManager),
13    Rcd(RcdServiceManager),
14    Sc(ScServiceManager),
15    Systemd(SystemdServiceManager),
16    WinSw(WinSwServiceManager),
17}
18
19macro_rules! using {
20    ($self:ident, $this:ident -> $expr:expr) => {{
21        match $self {
22            TypedServiceManager::Launchd($this) => $expr,
23            TypedServiceManager::OpenRc($this) => $expr,
24            TypedServiceManager::Rcd($this) => $expr,
25            TypedServiceManager::Sc($this) => $expr,
26            TypedServiceManager::Systemd($this) => $expr,
27            TypedServiceManager::WinSw($this) => $expr,
28        }
29    }};
30}
31
32impl ServiceManager for TypedServiceManager {
33    fn available(&self) -> io::Result<bool> {
34        using!(self, x -> x.available())
35    }
36
37    fn install(&self, ctx: ServiceInstallCtx) -> io::Result<()> {
38        using!(self, x -> x.install(ctx))
39    }
40
41    fn uninstall(&self, ctx: ServiceUninstallCtx) -> io::Result<()> {
42        using!(self, x -> x.uninstall(ctx))
43    }
44
45    fn start(&self, ctx: ServiceStartCtx) -> io::Result<()> {
46        using!(self, x -> x.start(ctx))
47    }
48
49    fn stop(&self, ctx: ServiceStopCtx) -> io::Result<()> {
50        using!(self, x -> x.stop(ctx))
51    }
52
53    fn level(&self) -> ServiceLevel {
54        using!(self, x -> x.level())
55    }
56
57    fn set_level(&mut self, level: ServiceLevel) -> io::Result<()> {
58        using!(self, x -> x.set_level(level))
59    }
60
61    fn status(&self, ctx: crate::ServiceStatusCtx) -> io::Result<crate::ServiceStatus> {
62        using!(self, x -> x.status(ctx))
63    }
64}
65
66impl TypedServiceManager {
67    /// Creates a new service using the specified type, falling back to selecting
68    /// based on native service manager for the current operating system if no type provided
69    pub fn target_or_native(kind: impl Into<Option<ServiceManagerKind>>) -> io::Result<Self> {
70        match kind.into() {
71            Some(kind) => Ok(Self::target(kind)),
72            None => Self::native(),
73        }
74    }
75
76    /// Creates a new service manager targeting the specific service manager kind using the
77    /// default service manager instance
78    pub fn target(kind: ServiceManagerKind) -> Self {
79        match kind {
80            ServiceManagerKind::Launchd => Self::Launchd(LaunchdServiceManager::default()),
81            ServiceManagerKind::OpenRc => Self::OpenRc(OpenRcServiceManager::default()),
82            ServiceManagerKind::Rcd => Self::Rcd(RcdServiceManager::default()),
83            ServiceManagerKind::Sc => Self::Sc(ScServiceManager::default()),
84            ServiceManagerKind::Systemd => Self::Systemd(SystemdServiceManager::default()),
85            ServiceManagerKind::WinSw => Self::WinSw(WinSwServiceManager::default()),
86        }
87    }
88
89    /// Attempts to select the native service manager for the current operating system
90    ///
91    /// * For MacOS, this will use [`LaunchdServiceManager`]
92    /// * For Windows, this will use [`ScServiceManager`]
93    /// * For BSD variants, this will use [`RcdServiceManager`]
94    /// * For Linux variants, this will use either [`SystemdServiceManager`] or [`OpenRcServiceManager`]
95    pub fn native() -> io::Result<Self> {
96        Ok(Self::target(ServiceManagerKind::native()?))
97    }
98
99    /// Consumes underlying [`ServiceManager`] and moves it onto the heap
100    pub fn into_box(self) -> Box<dyn ServiceManager> {
101        using!(self, x -> Box::new(x))
102    }
103
104    /// Returns true if [`ServiceManager`] instance is for `launchd`
105    pub fn is_launchd(&self) -> bool {
106        matches!(self, Self::Launchd(_))
107    }
108
109    /// Returns true if [`ServiceManager`] instance is for `OpenRC`
110    pub fn is_openrc(&self) -> bool {
111        matches!(self, Self::OpenRc(_))
112    }
113
114    /// Returns true if [`ServiceManager`] instance is for `rc.d`
115    pub fn is_rc_d(&self) -> bool {
116        matches!(self, Self::Rcd(_))
117    }
118
119    /// Returns true if [`ServiceManager`] instance is for `sc`
120    pub fn is_sc(&self) -> bool {
121        matches!(self, Self::Sc(_))
122    }
123
124    /// Returns true if [`ServiceManager`] instance is for `systemd`
125    pub fn is_systemd(&self) -> bool {
126        matches!(self, Self::Systemd(_))
127    }
128
129    /// Returns true if [`ServiceManager`] instance is for `winsw`
130    pub fn is_winsw(&self) -> bool {
131        matches!(self, Self::WinSw(_))
132    }
133}
134
135impl From<super::LaunchdServiceManager> for TypedServiceManager {
136    fn from(manager: super::LaunchdServiceManager) -> Self {
137        Self::Launchd(manager)
138    }
139}
140
141impl From<super::OpenRcServiceManager> for TypedServiceManager {
142    fn from(manager: super::OpenRcServiceManager) -> Self {
143        Self::OpenRc(manager)
144    }
145}
146
147impl From<super::RcdServiceManager> for TypedServiceManager {
148    fn from(manager: super::RcdServiceManager) -> Self {
149        Self::Rcd(manager)
150    }
151}
152
153impl From<super::ScServiceManager> for TypedServiceManager {
154    fn from(manager: super::ScServiceManager) -> Self {
155        Self::Sc(manager)
156    }
157}
158
159impl From<super::SystemdServiceManager> for TypedServiceManager {
160    fn from(manager: super::SystemdServiceManager) -> Self {
161        Self::Systemd(manager)
162    }
163}
164
165impl From<super::WinSwServiceManager> for TypedServiceManager {
166    fn from(manager: super::WinSwServiceManager) -> Self {
167        Self::WinSw(manager)
168    }
169}