git_policy_cli/path_bytes.rs
1//! What:
2//! Exact repository path bytes as the operating system takes them,
3//! and as text for messages.
4//! Why:
5//! Git allows any bytes in a file name.
6//! The commit path keeps a path as `Vec<u8>` from Git's listing to Git's next argument,
7//! so a name that is not UTF-8 reaches Git unchanged;
8//! only a message for a person shows the text with replacement characters.
9//!
10//! In TS you'd write (pseudocode):
11//! ```ts
12//! // const argument = Buffer.from(bytes); const shown = bytes.toString('utf8');
13//! ```
14
15use std::ffi::OsString;
16
17/// What:
18/// Raw path bytes as an operating-system string for a command line or a file name.
19/// `&[u8]` borrows the bytes;
20/// the result owns a copy.
21/// Why:
22/// A Git path is bytes,
23/// and only the platform decides how to pass them on:
24/// Unix takes them as they are,
25/// other platforms have text names, so the text with replacement characters is the closest name.
26///
27/// In TS you'd write (pseudocode):
28/// ```ts
29/// Buffer.from(bytes)
30/// ```
31pub fn os_from_path_bytes(bytes: &[u8]) -> OsString {
32 #[cfg(unix)]
33 {
34 /// The Unix conversion from raw bytes.
35 use std::os::unix::ffi::OsStringExt;
36 return OsString::from_vec(bytes.to_vec());
37 }
38 // UNTESTED ON WINDOWS: no gate compiles or runs this branch (the crate does not build for Windows; README, Requirements).
39 #[cfg(not(unix))]
40 {
41 return OsString::from(String::from_utf8_lossy(bytes).into_owned());
42 }
43}
44
45/// What:
46/// The readable text of path bytes for a message,
47/// with each invalid sequence replaced by U+FFFD.
48/// Why:
49/// Messages are text,
50/// and the exact bytes travel in the field next to them.
51///
52/// In TS you'd write (pseudocode):
53/// ```ts
54/// bytes.toString('utf8')
55/// ```
56pub fn path_message_text(bytes: &[u8]) -> String {
57 // `.into_owned()` copies the borrowed text only when no replacement was needed.
58 return String::from_utf8_lossy(bytes).into_owned();
59}
60
61/// Conversion controls stay out of the release executable.
62#[cfg(test)]
63#[path = "path_bytes_tests.rs"]
64mod tests;