Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 33 additions & 137 deletions src/router/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use bun_collections::{ArrayHashMap, StringHashMap};
use bun_core::strings;
use bun_paths::{self, PathBuffer, SEP, SEP_STR};
use bun_sys::Fd;
use bun_url::PathnameScanner;

use bun_http_types::URLPath::URLPath;

Expand All @@ -38,10 +37,7 @@ use bun_resolver::DirInfoRef;
use bun_resolver::fs as Fs;
use bun_resolver::fs::FileSystem;

// peechy schema types: `StringPointer` lives in `bun_core::schema::api` (T0);
// the route-config pair lives in `bun_options_types::schema::api`.
mod api {
pub(crate) use bun_core::schema::api::StringPointer;
pub(crate) use bun_options_types::schema::api::{LoadedRouteConfig, RouteConfig};
}

Expand Down Expand Up @@ -114,18 +110,6 @@ impl RouteConfig {
}
}

pub fn from_loaded_routes(loaded: api::LoadedRouteConfig) -> RouteConfig {
RouteConfig {
extensions: loaded.extensions,
routes_enabled: !loaded.dir.is_empty(),
static_dir_enabled: !loaded.static_dir.is_empty(),
dir: loaded.dir,
asset_prefix_path: loaded.asset_prefix,
static_dir: loaded.static_dir,
possible_dirs: Box::default(),
}
}

pub fn from_api(router_: &api::RouteConfig) -> Result<RouteConfig, CoreError> {
use bun_core::strings::{trim_left, trim_right};

Expand Down Expand Up @@ -230,22 +214,6 @@ impl<'a> Router<'a> {
self.routes.list.items_filepath()
}

pub fn get_public_paths(&self) -> &[&'static [u8]] {
self.routes.list.items_public_path()
}

pub fn route_index_by_hash(&self, hash: u32) -> Option<usize> {
if hash == INDEX_ROUTE_HASH {
return self.routes.index_id;
}

self.routes
.list
.items_hash()
.iter()
.position(|&h| h == hash)
}

pub fn get_names(&self) -> &[&'static [u8]] {
self.routes.list.items_name()
}
Comment thread
robobun marked this conversation as resolved.
Expand Down Expand Up @@ -333,8 +301,6 @@ struct RouteIndex {
name: &'static [u8],
match_name: &'static [u8],
filepath: &'static [u8],
public_path: &'static [u8],
hash: u32,
}

// TODO(b2-blocked): bun_collections::MultiArrayElement derive — proc-macro not
Expand All @@ -350,8 +316,6 @@ pub struct RouteIndexList {
name: Vec<&'static [u8]>,
match_name: Vec<&'static [u8]>,
filepath: Vec<&'static [u8]>,
public_path: Vec<&'static [u8]>,
hash: Vec<u32>,
}

impl RouteIndexList {
Expand All @@ -360,17 +324,13 @@ impl RouteIndexList {
self.name.reserve_exact(cap);
self.match_name.reserve_exact(cap);
self.filepath.reserve_exact(cap);
self.public_path.reserve_exact(cap);
self.hash.reserve_exact(cap);
Ok(())
}
pub(crate) fn push(&mut self, item: RouteIndex) {
self.route.push(item.route);
self.name.push(item.name);
self.match_name.push(item.match_name);
self.filepath.push(item.filepath);
self.public_path.push(item.public_path);
self.hash.push(item.hash);
}
#[inline]
pub fn len(&self) -> usize {
Expand All @@ -392,14 +352,6 @@ impl RouteIndexList {
pub fn items_filepath(&self) -> &[&'static [u8]] {
&self.filepath
}
#[inline]
pub fn items_public_path(&self) -> &[&'static [u8]] {
&self.public_path
}
#[inline]
pub fn items_hash(&self) -> &[u32] {
&self.hash
}
}

pub struct Routes {
Expand All @@ -422,7 +374,6 @@ pub struct Routes {
/// `list.route`). Stored as `NonNull` (not `&'a Route`) so `Routes` claims
/// no borrow it doesn't actually take; matches `static_` above.
pub index: Option<NonNull<Route>>,
pub index_id: Option<usize>,

// allocator dropped — global mimalloc
pub config: RouteConfig,
Expand All @@ -440,7 +391,6 @@ impl Default for Routes {
dynamic_len: 0,
static_: StringHashMap::new(),
index: None,
index_id: Some(0),
config: RouteConfig::default(),
client_framework_enabled: false,
}
Expand Down Expand Up @@ -758,17 +708,11 @@ impl<'a> RouteLoader<'a> {
index_id = Some(i);
}

let (filepath, match_name, public_path) = (
route.abs_path.as_bytes(),
route.match_name.as_bytes(),
route.public_path.as_bytes(),
);
let (filepath, match_name) = (route.abs_path.as_bytes(), route.match_name.as_bytes());
route_list.push(RouteIndex {
name: route.name,
filepath,
match_name,
public_path,
hash: route.full_hash,
route,
});
}
Expand All @@ -794,7 +738,6 @@ impl<'a> RouteLoader<'a> {
// pointer.
index: this.index,
config,
index_id,
client_framework_enabled: false,
}
}
Expand Down Expand Up @@ -939,14 +882,6 @@ impl TinyPtr {
}
}

#[inline]
pub fn to_string_pointer(self) -> api::StringPointer {
api::StringPointer {
offset: self.offset() as u32,
length: self.len() as u32,
}
}

#[inline]
pub fn eql(a: TinyPtr, b: TinyPtr) -> bool {
a == b
Expand Down Expand Up @@ -994,19 +929,11 @@ pub struct Route {

pub abs_path: AbsPath,

/// URL-safe path for the route's transpiled script relative to project's top level directory
/// - It might not share a prefix with the absolute path due to symlinks.
/// - It has a leading slash
pub public_path: Interned,

pub kind: pattern::Tag,

pub has_uppercase: bool,
}

// TODO(b1): inherent assoc types unstable; module-level alias instead.
pub type RoutePtr = TinyPtr;

impl Route {
pub const INDEX_ROUTE_NAME: &'static [u8] = b"/";

Expand Down Expand Up @@ -1101,56 +1028,41 @@ impl Route {
let is_index = name.is_empty();

let mut has_uppercase = false;
// NOTE: reshaped for borrowck — both arms intern via DirnameStore
// (process-lifetime arena → `&'static`), so the post-if bindings are
// 'static and the route_file_buf borrow is dropped before the
// abs-path block below needs it mutably.
let (public_path, name, match_name): (&'static [u8], &'static [u8], &'static [u8]) =
if !name.is_empty() {
validation_result = match Pattern::validate(&name[1..], log) {
Some(v) => v,
None => return None,
};

let mut name_i: usize = 0;
while !has_uppercase && name_i < public_path.len() {
has_uppercase = public_path[name_i] >= b'A' && public_path[name_i] <= b'Z';
name_i += 1;
}
// NOTE: the non-index arm interns via DirnameStore (process-lifetime
// arena → `&'static`), so the post-if bindings drop the
// route_file_buf borrow before the abs-path block reborrows it.
let (name, match_name): (&'static [u8], &'static [u8]) = if !name.is_empty() {
validation_result = match Pattern::validate(&name[1..], log) {
Some(v) => v,
None => return None,
};

let mut name_i: usize = 0;
while !has_uppercase && name_i < public_path.len() {
has_uppercase = public_path[name_i] >= b'A' && public_path[name_i] <= b'Z';
name_i += 1;
}

let name_offset = name.as_ptr() as usize - public_path.as_ptr() as usize;
let name_len = name.len();

// NOTE: DirnameStore::append returns `&'static [u8]` (process-
// lifetime arena), so rebinding here drops the borrow on
// `route_file_buf` and avoids needing lifetime transmutes
// below.
let dirname_store = FileSystem::instance().dirname_store();
let public_path: &'static [u8] =
dirname_store.append(public_path).expect("unreachable");
let name: &'static [u8] = &public_path[name_offset..][0..name_len];
let match_name: &'static [u8] = if has_uppercase {
dirname_store
.append_lower_case(&name[1..])
.expect("unreachable")
} else {
&name[1..]
};

debug_assert!(match_name[0] != b'/');
debug_assert!(name[0] == b'/');
(public_path, name, match_name)
// NOTE: DirnameStore::append returns `&'static [u8]`, so
// rebinding drops the route_file_buf borrow without a
// lifetime transmute.
let dirname_store = FileSystem::instance().dirname_store();
let name: &'static [u8] = dirname_store.append(name).expect("unreachable");
let match_name: &'static [u8] = if has_uppercase {
dirname_store
.append_lower_case(&name[1..])
.expect("unreachable")
} else {
let dirname_store = FileSystem::instance().dirname_store();
let public_path: &'static [u8] =
dirname_store.append(public_path).expect("unreachable");
(
public_path,
Route::INDEX_ROUTE_NAME,
Route::INDEX_ROUTE_NAME,
)
&name[1..]
};

debug_assert!(match_name[0] != b'/');
debug_assert!(name[0] == b'/');
(name, match_name)
} else {
(Route::INDEX_ROUTE_NAME, Route::INDEX_ROUTE_NAME)
};

if abs_path_str.is_empty() {
// The reads of `cache().fd` and the `set_abs_path` write below
// rewrite the cached `Entry`; serialize them on the per-entry
Expand Down Expand Up @@ -1259,14 +1171,13 @@ impl Route {
#[cfg(all(debug_assertions, windows))]
{
debug_assert!(!strings::index_of_char(name, b'\\').is_some());
debug_assert!(!strings::index_of_char(public_path, b'\\').is_some());
debug_assert!(!strings::index_of_char(match_name, b'\\').is_some());
debug_assert!(!strings::index_of_char(abs_path.as_bytes(), b'\\').is_some());
// SAFETY: read-only reborrow; the `&mut` write above is dead.
debug_assert!(!strings::index_of_char(unsafe { &*entry }.base(), b'\\').is_some());
}

// NOTE: name/match_name/public_path are already `&'static` via
// NOTE: name/match_name are already `&'static` via
// DirnameStore::append above. `entry.base()` borrows the entry (it
// may be inline-stored for ≤31-byte names); intern it
// explicitly to get `&'static` without a lifetime transmute.
Expand All @@ -1279,7 +1190,6 @@ impl Route {
Some(Route {
name,
basename,
public_path: Interned::from_static(public_path),
match_name: Interned::from_static(match_name),
full_hash: if is_index {
INDEX_ROUTE_HASH
Expand Down Expand Up @@ -1473,20 +1383,6 @@ impl<'a> Match<'a> {
unsafe { (*self.params).len() > 0 }
}

pub fn params_iterator(&self) -> PathnameScanner<'_> {
// SAFETY: see `has_params`.
PathnameScanner::init(self.pathname, self.name, unsafe { &*self.params })
}

pub fn name_with_basename<'s>(file_path: &'s [u8], dir: &[u8]) -> &'s [u8] {
let mut name = file_path;
if let Some(i) = strings::index_of(name, dir) {
name = &name[i + dir.len()..];
}

&name[0..name.len() - bun_paths::extension(name).len()]
}

pub fn pathname_without_leading_slash(&self) -> &[u8] {
strings::trim_left(self.pathname, b"/")
}
Expand Down
Loading