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}