shellexpand/wtraits.rs
1//! Type aliases and trait definitions for internal traits - **instantiated twice**
2//!
3//! Like `funcs`, this is instantiated twice, as
4//! [`crate::strings::wtraits`] and [`crate::path::wtraits`].
5//!
6//! He type aliases, and even traits, here,
7//! are all different, in the two contexts.
8
9#![cfg_attr(not(feature = "full"), allow(dead_code))]
10
11pub(crate) use std::borrow::Cow;
12pub(crate) use std::fmt;
13pub(crate) use std::path::PathBuf;
14
15/// External borrowed form; inputs are generally of type `AsRef<Xstr>`
16///
17/// `str` for strings; [`Path`](std::path::Path) for paths.
18pub(crate) type Xstr = super::Xstr;
19
20/// Working, possibly-owned, form of the input
21///
22/// Usually converted from `AsRef<`[`Xstr`]`>`,
23/// using [`.into_winput()`](AsRefXstrExt::into_winput).
24///
25/// For strings, this is simply `&'s str`;
26///
27/// For paths, this is `Cow<'s, RawOsStr>`.
28/// This is because it can be necessary to copy-convert the input
29/// to a different representation.
30/// (This happens only on Windows, whose native character encoding UTF-16, which is deranged;
31/// on Unix, I believe this is always `Cow::Borrowed`.)
32pub(crate) type WInput<'s> = super::WInput<'s>;
33
34/// Working, definitely-borrowed, form of the input
35///
36/// Most input-processing, such as slicing up the input, is done with this type.
37///
38/// `str` for strings, `RawOsStr` for paths.
39pub(crate) type Wstr = super::Wstr;
40
41/// Output accumulator (owned)
42///
43/// As we process input chunks, we add them to this.
44///
45/// This type doesn't provide an easy way to rescan it again -
46/// but we generally only want to scan things once.
47///
48/// Also used for error reporting, in `LookupError`.
49///
50/// `String`, or [`OsString`](std::ffi::OsString).
51pub(crate) type OString = super::OString;
52
53/// Owned version of Xstr
54///
55/// `String`, or `PathBuf`.
56///
57/// Currently used only as the return value from `home_dir()`.
58pub(crate) type XString = <Xstr as ToOwned>::Owned;
59
60/// Extra bounds on [`Xstr`] (and hence, restrictions on [`XString`])
61///
62/// This is implemented only for the single type `Xstr` (ie, for `str`, or `Path`).
63///
64/// The bound `str: AsRef<self>`
65/// declares that we can cheaply borrow a normal string as an `Xstr`.
66///
67/// The bound `PathBuf: `[`PathBufExt`]
68/// declares that
69/// `Pathbuf.`[`try_into_xstring()`](PathBufExt::try_into_xstring) is available -
70/// ie, that you can try to obtain an `XString` from a `PathBuf`,
71/// which is relevant for home directories and tilde substitution.
72///
73/// These bounds (and therefore this trait), including the supertrait,
74/// are not needed for the code to compile,
75/// since we don't have significant amounts of generic code.
76/// But they serve as compiler-checked documentation.
77pub(crate) trait XstrRequirements: AsRefXstrExt where str: AsRef<Self>, PathBuf: PathBufExt {
78}
79
80/// Methods on `AsRef<`[`Xstr`]`>`
81///
82/// These methods are used by the implementation in `funcs`
83/// to convert the input into the working form,
84/// or, to be able to return it unmodified.
85///
86/// This is implemented (only) for `S: AsRef<Xstr>`.
87pub(crate) trait AsRefXstrExt {
88 /// Convert an input string into our working form
89 fn into_winput(&self) -> WInput;
90
91 /// Convert an unmodified input string back into the public output type
92 ///
93 /// Called when inspection of the string tells us we didn't need to make any substitutions.
94 fn into_ocow(&self) -> Cow<'_, Xstr>;
95}
96
97/// Extension trait on `PathBuf`
98///
99/// Implemented separately by the code for
100/// strings (returning `Option<String>`)
101/// and paths (returning `Option<PathBuf>`)
102pub(crate) trait PathBufExt {
103 /// Converts a `PathBuf` into an `XString` (input string type), if possible
104 ///
105 /// We might not be able to represent a non-Unicode path.
106 /// In that case, this function returns `None`.
107 fn try_into_xstring(self) -> Option<XString>;
108}
109
110/// Methods (and bounds) on `Wstr`
111///
112/// `funcs` may also use inherent methods, including slicing,
113/// provided they are implemented for both `str` and `RawOsString`,
114/// with suitable semantics.
115///
116/// The bound declares that `&str` or `&RawOsStr` implements `WstrRefExt`
117/// so that [`.chars_approx()`](WstrRefExt::chars_approx) is available.
118pub(crate) trait WstrExt: where for <'s> &'s Self: WstrRefExt {
119 /// Turn something which maybe derefs to a `Wstr` into a `Wstr`
120 ///
121 /// This allows us to use method call autoderef.
122 ///
123 /// We want this at call sites that have [`WInput`],
124 /// which don't otherwise know whether to deref:
125 /// for strings, `WInput` is `&str`,
126 /// and is therefore already a `&Wstr` (which is also `&str`).
127 /// whereas for paths, `WInput` is `Cow<Path>` which derefs to `&Wstr` (ie `&Path`).
128 fn as_wstr(&self) -> &Self { self }
129
130 /// Get this bit of the input as a plain string, if it is Unicode
131 ///
132 /// Used for variable name lookups. Our variable lookup API passes Unicode variable names
133 /// to the caller.
134 /// (Any non-Unicode we find is therefore, by definition, an undefined variable).
135 fn as_str(&self) -> Option<&str>;
136
137 /// Length, in a form suitable for slicing
138 ///
139 /// Calling this `len` is only reasonable because the `Wstr` type either
140 /// doesn't have a `len` method of its own (true of `RawOsStr`, for paths),
141 /// or has one which works the same (true of `str`, for strings).
142 fn len(&self) -> usize;
143
144 /// Convert to an `OString`, as used for error reporting etc.
145 fn to_ostring(&self) -> OString;
146
147 /// Like `str::strip_prefix`, but available on our str MSRV 1.31
148 fn strip_prefix(&self, c: char) -> Option<&Self>;
149}
150
151/// Method on the reference [`&Wstr`](Wstr)
152///
153/// This can't be in the main [`WstrExt`] trait because
154/// the type `Chars` would have a lifetime -
155/// ie it would be a GAT, which is very new in Rust and we don't want to rely on.
156pub(crate) trait WstrRefExt {
157 /// Iterator over characters
158 type Chars: Iterator<Item=char> + CharsExt;
159
160 /// Iterate over, roughly, characters
161 ///
162 /// This is not guaranteed to work very well in the presence of non-Unicode input,
163 /// or strange encodings.
164 ///
165 /// The properties we rely on are:
166 ///
167 /// * Where the input contains ASCII characters `$` `{` `}` `~` `/` `\`,
168 /// they come out of the iterator in the right place.
169 ///
170 /// * Where the input contains characters that are found in variable names the user
171 /// wants to substitute, they come out properly in the right place,
172 /// and they are recognised as Unicode letters.
173 ///
174 /// * The return value from [`.wstr_len()`](CharsExt::wstr_len)
175 /// can be used in slicing calculations.
176 fn chars_approx(self) -> Self::Chars;
177}
178
179/// Methods on the characters iterator from [`Wstr.chars_approx()`](WstrRefExt::chars_approx)
180pub(crate) trait CharsExt {
181 fn wstr_len(&self) -> usize;
182}
183
184/// Methods on [`OString`]
185///
186/// `funcs` may also use inherent methods,
187/// provided they are implemented for both `String` and `RawOsString`,
188/// with suitable semantics.
189pub(crate) trait OStringExt {
190 /// Append a plain `str` (used for literal text)
191 fn push_str(&mut self, x: &str);
192
193 /// Append a `Wstr` (used for copying through pieces of the input)
194 fn push_wstr(&mut self, x: &Wstr);
195
196 /// Append an `Xstr` (used for copying through variable lookup results)
197 fn push_xstr(&mut self, x: &Xstr);
198
199 /// Convert an output string we have been accumulating into the public output type
200 fn into_ocow(self) -> Cow<'static, Xstr>;
201
202 /// Write this input string in a possibly-lossy way, for use in error messages
203 fn display_possibly_lossy(&self, f: &mut fmt::Formatter) -> fmt::Result;
204}