blob: ac2bfeb2d2bacc00d112e3620121c1937bd6f8cf [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::borrow::Cow;
fn is_absolute(p: &str) -> bool {
let mut bytes = p.bytes();
let b = match bytes.next() {
Some(b) => b,
None => return false,
};
match b {
// Unix paths
b'/' => true,
// Windows paths starting with drive letter like `C:`
b'A'..=b'Z' | b'a'..=b'z' => bytes.next() == Some(b':'),
// Windows paths starting with `\\` (UNC)
b'\\' => bytes.next() == Some(b'\\'),
_ => false,
}
}
fn strip_prefix<'a>(p: &'a str, prefix: &'static str) -> Option<&'a str> {
if p.starts_with(prefix) {
Some(unsafe { p.get_unchecked(prefix.len()..) })
} else {
None
}
}
pub struct Path<'a>(Cow<'a, str>);
impl<'a> Path<'a> {
pub fn new(s: Cow<'a, str>) -> Self {
assert!(is_absolute(&s));
Path(s)
}
pub fn push(&mut self, p2: Cow<'a, str>) {
if is_absolute(&p2) {
self.0 = p2;
} else {
let p1 = self.0.to_mut();
if p1.starts_with('/') {
// Assume Unix absolute path, add slash if it's not there yet.
if !p1.ends_with('/') {
p1.push('/');
}
} else {
// Assume Windows absolute path, add backslash if not there yet.
if !p1.ends_with('\\') {
p1.push('\\');
}
}
p1.push_str(&p2);
}
}
pub fn borrow(&self) -> Path {
Path(Cow::Borrowed(&self.0))
}
pub fn to_uri(&self) -> String {
let path = &self.0;
if let Some(path) = strip_prefix(&path, "/rustc/") {
// TODO: avoid hardcoding this, and instead let users configure
// path replacements in DevTools UI.
format!("https://raw.githubusercontent.com/rust-lang/rust/{}", path)
} else if path.starts_with('/') {
// Unix-style path
format!("file://{}", path)
} else {
// Windows-style path
format!("file:///{}", path)
}
}
}