///|
/// Checks whether `path` is absolute for `platform`.
fn is_absolute_path(platform : Platform, path : String) -> Bool {
if path.is_empty() {
return false
}
match platform {
Windows => is_windows_absolute_path(path)
MacOS | Linux => is_unix_absolute_path(path)
Unsupported => false
}
}
///|
/// Checks the Unix absolute-path form accepted by the package.
fn is_unix_absolute_path(path : String) -> Bool {
path.code_unit_at(0) == '/'
}
///|
/// Checks the Windows absolute-path forms accepted by the package.
fn is_windows_absolute_path(path : String) -> Bool {
is_windows_drive_absolute_path(path) || is_windows_unc_path(path)
}
///|
/// Checks the `C:\path` and `C:/path` Windows absolute-path forms.
fn is_windows_drive_absolute_path(path : String) -> Bool {
path.length() >= 3 &&
is_ascii_letter(path.code_unit_at(0)) &&
path.code_unit_at(1) == ':' &&
is_windows_separator(path.code_unit_at(2))
}
///|
/// Checks the UNC `\\server\share` Windows absolute-path form.
fn is_windows_unc_path(path : String) -> Bool {
path.length() >= 2 &&
path.code_unit_at(0) == '\\' &&
path.code_unit_at(1) == '\\'
}
///|
/// Checks whether `code_unit` is a Windows path separator.
fn is_windows_separator(code_unit : UInt16) -> Bool {
code_unit == '\\' || code_unit == '/'
}
///|
/// Checks whether `code_unit` is an ASCII letter.
fn is_ascii_letter(code_unit : UInt16) -> Bool {
let code = code_unit.to_int()
(code >= 'a'.to_int() && code <= 'z'.to_int()) ||
(code >= 'A'.to_int() && code <= 'Z'.to_int())
}
///|
/// Trims leading and trailing Unicode whitespace.
fn trim_text(text : String) -> String {
text.trim().to_owned()
}
///|
/// Validates the replacement source path against the current platform.
fn validate_replacement_path(
platform : Platform,
replacement_path : String,
current_executable_path : String,
) -> Result[String, ReplaceSelfError] {
if platform == Unsupported {
return Err(UnsupportedPlatform(platform))
}
let trimmed = trim_text(replacement_path)
if trimmed.is_empty() {
return Err(EmptyReplacementPath)
}
if !is_absolute_path(platform, trimmed) {
return Err(RelativeReplacementPath(trimmed))
}
if trimmed == current_executable_path {
return Err(ReplacementMatchesCurrentExecutable(trimmed))
}
Ok(trimmed)
}