interprocess/local_socket/name/type.rs
1//! Construction of local socket names, facilitating local socket implementation dispatch.
2//!
3//! The traits [`PathNameType`] and [`NamespacedNameType`] are implemented on uninhabited tag types
4//! and are to be used via [`ToFsName`](super::ToFsName) and [`ToNsName`](super::ToNsName)
5//! respectively. They are also sealed (cannot be implemented outside of Interprocess).
6//!
7//! The name type you choose affects what local socket implementation will be used. See the
8//! documentation on the tag types to learn more.
9
10#[cfg(unix)]
11use std::ffi::CStr;
12use {
13 super::Name,
14 crate::Sealed,
15 std::{borrow::Cow, ffi::OsStr, io},
16};
17
18impmod! {local_socket::name_type as n_impl}
19
20/// Mappings from string types to [local socket names](Name).
21///
22/// Types that implement this trait are [uninhabited] type-level markers: those which implement
23/// [`PathNameType`] serve as generic arguments for
24/// [`ToFsName::to_fs_name()`](super::ToFsName::to_fs_name), while those which implement
25/// [`NamespacedNameType`] are used with [`ToNsName::to_ns_name()`](super::ToNsName::to_ns_name).
26///
27/// [uninhabited]: https://doc.rust-lang.org/reference/glossary.html#uninhabited
28///
29/// **It is a breaking change for a mapping to meaningfully change.** More concretely, if a name
30/// produced by this mapping from some input results in a valid listener via
31/// [server creation](super::super::ListenerOptions) or successfully locates one via
32/// [client creation](super::super::traits::Stream::connect), the name type will continue to map
33/// that input to the same name, for the OS's definition of "same".
34#[allow(private_bounds)]
35pub trait NameType: Copy + std::fmt::Debug + Eq + Send + Sync + Unpin + Sealed {
36 /// Whether the name type is supported within the runtime circumstances of the program.
37 ///
38 /// May entail querying support status from the OS, returning `false` in the event of an OS
39 /// error.
40 fn is_supported() -> bool;
41}
42
43/// [Mappings](NameType) from paths to [local socket names](Name).
44///
45/// See [`ToFsName::to_fs_name()`](super::ToFsName::to_fs_name).
46pub trait PathNameType<S: ToOwned + ?Sized>: NameType {
47 /// Maps the given path to a local socket name, failing if the resulting name is unsupported by
48 /// the underlying OS.
49 ///
50 /// The idiomatic way to use this is [`ToFsName::to_fs_name()`](super::ToFsName::to_fs_name).
51 fn map(path: Cow<'_, S>) -> io::Result<Name<'_>>;
52}
53/// [Mappings](NameType) from strings to [local socket names](Name).
54///
55/// See [`ToNsName::to_ns_name()`](super::ToNsName::to_ns_name).
56pub trait NamespacedNameType<S: ToOwned + ?Sized>: NameType {
57 /// Maps the given string to a local socket name, failing if the resulting name is unsupported
58 /// by the underlying OS.
59 ///
60 /// The idiomatic way to use this is [`ToNsName::to_ns_name()`](super::ToNsName::to_ns_name).
61 fn map(name: Cow<'_, S>) -> io::Result<Name<'_>>;
62}
63
64tag_enum!(
65/// Consistent platform-specific mapping from filesystem paths to local socket names.
66///
67/// This name type, like [`GenericNamespaced`] is designed to be always supported on all platforms,
68/// whatever it takes. What follows below is a complete description of how that is implemented.
69///
70/// ## Platform-specific behavior
71/// ### Windows
72/// For paths that start with `\\.\pipe\`, maps them to named pipe names without performing any
73/// transformations. Attempting to map any other type of path, including a normalization-bypassing
74/// path (`\\?\`) currently returns an error.
75///
76/// ### Unix
77/// Resolves to filesystem paths to Unix domain sockets without performing any transformations.
78GenericFilePath);
79impl NameType for GenericFilePath {
80 fn is_supported() -> bool { true }
81}
82impl PathNameType<OsStr> for GenericFilePath {
83 #[inline]
84 fn map(path: Cow<'_, OsStr>) -> io::Result<Name<'_>> { n_impl::map_generic_path_osstr(path) }
85}
86#[cfg(unix)]
87#[cfg_attr(feature = "doc_cfg", doc(cfg(unix)))]
88impl PathNameType<CStr> for GenericFilePath {
89 #[inline]
90 fn map(path: Cow<'_, CStr>) -> io::Result<Name<'_>> { n_impl::map_generic_path_cstr(path) }
91}
92
93tag_enum!(
94/// Consistent platform-specific mapping from arbitrary OS strings to local socket names.
95///
96/// This name type, like [`GenericFilePath`] is designed to be always supported on all platforms,
97/// whatever it takes. What follows below is a complete description of how that is implemented.
98///
99/// ## Platform-specific behavior
100/// ### Windows
101/// Resolves to named pipe names by prepending `\\.\pipe\` (thus, only local named pipes are
102/// addressable).
103///
104/// ### Linux
105/// Resolves to the abstract namespace with no string transformations and thus has a maximum length
106/// of 107 bytes.
107///
108/// ### Other Unices
109/// Resolves to filesystem paths by prepending `/tmp/`.
110GenericNamespaced);
111impl NameType for GenericNamespaced {
112 fn is_supported() -> bool { true }
113}
114impl NamespacedNameType<OsStr> for GenericNamespaced {
115 #[inline]
116 fn map(name: Cow<'_, OsStr>) -> io::Result<Name<'_>> {
117 n_impl::map_generic_namespaced_osstr(name)
118 }
119}
120#[cfg(unix)]
121#[cfg_attr(feature = "doc_cfg", doc(cfg(unix)))]
122impl NamespacedNameType<CStr> for GenericNamespaced {
123 #[inline]
124 fn map(name: Cow<'_, CStr>) -> io::Result<Name<'_>> {
125 n_impl::map_generic_namespaced_cstr(name)
126 }
127}