changeset 6:a7893294e9b2

Make the crate compilable on non-linux systems This makes the crate compile on other operating systems. Since systemd is only supported on Linux, it simply disables systemd features on other systems. The API is still the same, just parsing `systemd://` string will return an error.
author Martin Habovstiak <martin.habovstiak@gmail.com>
date Fri, 27 Nov 2020 16:15:57 +0100
parents 27456533853e
children 9731ff589d9c
files Cargo.toml README.md src/error.rs src/lib.rs
diffstat 4 files changed, 45 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/Cargo.toml	Fri Nov 27 15:18:25 2020 +0100
+++ b/Cargo.toml	Fri Nov 27 16:15:57 2020 +0100
@@ -9,12 +9,14 @@
 [features]
 serde = ["serde_crate", "serde_str_helpers"]
 
+[target.'cfg(target_os = "linux")'.dependencies]
+libsystemd = "0.2.1"
+
 [dependencies]
 thiserror = "1.0.22"
 serde_crate = { package = "serde", version = "1.0.117", optional = true, features = ["derive"] }
 serde_str_helpers = { version = "0.1.0", optional = true }
 parse_arg = { version = "0.1.4", optional = true }
-libsystemd = "0.2.1"
 lazy_static = "1.4.0"
 tokio_0_2 = { package = "tokio", version = "0.2", optional = true, features = ["tcp", "dns"] }
 tokio_0_3 = { package = "tokio", version = "0.3", optional = true, features = ["net"] }
--- a/README.md	Fri Nov 27 15:18:25 2020 +0100
+++ b/README.md	Fri Nov 27 16:15:57 2020 +0100
@@ -13,6 +13,9 @@
 Thanks to this the change to your code should be minimal - parsing will continue to work, it'll just allow a new format.
 You only need to change the code to use `SocketAddr::bind()` instead of `TcpListener::bind()` for binding.
 
+You also don't need to worry about conditional compilation to ensure OS compatibility.
+This crate handles that for you by disabling systemd on non-linux systems.
+
 Further, the crate also provides methods for binding `tokio` 0.2, 0.3, and `async_std` sockets if the appropriate features are
 activated.
 
--- a/src/error.rs	Fri Nov 27 15:18:25 2020 +0100
+++ b/src/error.rs	Fri Nov 27 16:15:57 2020 +0100
@@ -19,10 +19,15 @@
 pub(crate) enum ParseErrorInner {
     #[error("failed to parse socket address")]
     ResolvAddr(#[from] crate::resolv_addr::ResolvAddrError),
+    #[cfg(linux)]
     #[error("invalid character '{c}' in systemd socket name {string} at position {pos}")]
     InvalidCharacter { string: String, c: char, pos: usize, },
+    #[cfg(linux)]
     #[error("systemd socket name {string} is {len} characters long which is more than the limit 255")]
     LongSocketName { string: String, len: usize, },
+    #[cfg(not(linux))]
+    #[error("can't parse {0} because systemd is not supported on this operating system")]
+    SystemdUnsupported(String),
 }
 
 /// Error that can occur during parsing of `SocketAddr` from a `OsStr`/`OsString`
@@ -60,11 +65,14 @@
     BindFailed { addr: std::net::SocketAddr, #[source] error: io::Error, },
     #[error("failed to bind {addr}")]
     BindOrResolvFailed { addr: crate::resolv_addr::ResolvAddr, #[source] error: io::Error, },
+    #[cfg(linux)]
     #[error("failed to receive descriptors with names")]
     ReceiveDescriptors(#[source] crate::systemd_sockets::Error),
     #[error("missing systemd socket {0} - a typo or an attempt to bind twice")]
+    #[cfg(linux)]
     MissingDescriptor(String),
     #[error("the systemd socket {0} is not an internet socket")]
+    #[cfg(linux)]
     NotInetSocket(String),
 }
 
--- a/src/lib.rs	Fri Nov 27 15:18:25 2020 +0100
+++ b/src/lib.rs	Fri Nov 27 16:15:57 2020 +0100
@@ -11,6 +11,9 @@
 //! Thanks to this the change to your code should be minimal - parsing will continue to work, it'll just allow a new format.
 //! You only need to change the code to use `SocketAddr::bind()` instead of `TcpListener::bind()` for binding.
 //!
+//! You also don't need to worry about conditional compilation to ensure OS compatibility.
+//! This crate handles that for you by disabling systemd on non-linux systems.
+//!
 //! Further, the crate also provides methods for binding `tokio` 0.2, 0.3, and `async_std` sockets if the appropriate features are
 //! activated.
 //! 
@@ -62,6 +65,10 @@
 use crate::error::*;
 use crate::resolv_addr::ResolvAddr;
 
+#[cfg(not(linux))]
+use std::convert::Infallible as Never;
+
+#[cfg(linux)]
 pub(crate) mod systemd_sockets {
     use std::fmt;
     use std::sync::Mutex;
@@ -217,11 +224,18 @@
     // rules.
     fn try_from_generic<'a, T>(string: T) -> Result<Self, ParseError> where T: 'a + std::ops::Deref<Target=str> + Into<String> {
         if string.starts_with(SYSTEMD_PREFIX) {
-            let name_len = string.len() - SYSTEMD_PREFIX.len();
-            match string[SYSTEMD_PREFIX.len()..].chars().enumerate().find(|(_, c)| !c.is_ascii() || *c < ' ' || *c == ':') {
-                None if name_len <= 255 => Ok(SocketAddr(SocketAddrInner::Systemd(string.into()))),
-                None => Err(ParseErrorInner::LongSocketName { string: string.into(), len: name_len }.into()),
-                Some((pos, c)) => Err(ParseErrorInner::InvalidCharacter { string: string.into(), c, pos, }.into()),
+            #[cfg(linux)]
+            {
+                let name_len = string.len() - SYSTEMD_PREFIX.len();
+                match string[SYSTEMD_PREFIX.len()..].chars().enumerate().find(|(_, c)| !c.is_ascii() || *c < ' ' || *c == ':') {
+                    None if name_len <= 255 => Ok(SocketAddr(SocketAddrInner::Systemd(string.into()))),
+                    None => Err(ParseErrorInner::LongSocketName { string: string.into(), len: name_len }.into()),
+                    Some((pos, c)) => Err(ParseErrorInner::InvalidCharacter { string: string.into(), c, pos, }.into()),
+                }
+            }
+            #[cfg(not(linux))]
+            {
+                Err(ParseErrorInner::SystemdUnsupported(string.into()).into())
             }
         } else {
             match string.parse() {
@@ -231,6 +245,7 @@
         }
     }
 
+    #[cfg(linux)]
     fn get_systemd(socket_name: String) -> Result<(std::net::TcpListener, SocketAddrInner), BindError> {
         use libsystemd::activation::IsType;
         use std::os::unix::io::{FromRawFd, IntoRawFd};
@@ -248,6 +263,13 @@
             }
         }
     }
+
+    // This approach makes the rest of the code much simpler as it doesn't require sprinkling it
+    // with #[cfg(linux)] yet still statically guarantees it won't execute.
+    #[cfg(not(linux))]
+    fn get_systemd(socket_name: Never) -> Result<(std::net::TcpListener, SocketAddrInner), BindError> {
+        match socket_name {}
+    }
 }
 
 /// Displays the address in format that can be parsed again.
@@ -275,7 +297,11 @@
 enum SocketAddrInner {
     Ordinary(std::net::SocketAddr),
     WithHostname(resolv_addr::ResolvAddr),
+    #[cfg(linux)]
     Systemd(String),
+    #[cfg(not(linux))]
+    #[allow(dead_code)]
+    Systemd(Never),
 }
 
 const SYSTEMD_PREFIX: &str = "systemd://";