use bun_collections::array_hash_map::ArrayHashAdapter;
use bun_collections::multi_array_list;
use bun_collections::{ArrayHashMap, DynamicBitSetUnmanaged, MultiArrayList};
use super::base::IndexInt;
use super::use_directive::UseDirective;
#[derive(Clone, Copy)]
pub struct ServerComponentBoundary {
pub use_directive: UseDirective,
pub source_index: IndexInt,
pub reference_source_index: IndexInt,
pub ssr_source_index: IndexInt,
}
bun_collections::multi_array_columns! {
pub trait ServerComponentBoundaryColumns for ServerComponentBoundary {
use_directive: UseDirective,
source_index: IndexInt,
reference_source_index: IndexInt,
ssr_source_index: IndexInt,
}
}
#[derive(Default)]
pub struct List {
pub list: MultiArrayList<ServerComponentBoundary>,
pub map: Map,
}
type Map = ArrayHashMap<(), ()>;
impl List {
pub fn put(
&mut self,
source_index: IndexInt,
use_directive: UseDirective,
reference_source_index: IndexInt,
ssr_source_index: IndexInt,
) -> Result<(), bun_alloc::AllocError> {
self.list.append(ServerComponentBoundary {
source_index,
use_directive,
reference_source_index,
ssr_source_index,
})?;
let gop = self.map.get_or_put_adapted(
&source_index,
&Adapter {
source_indices: self.list.items::<"source_index", IndexInt>(),
},
)?;
debug_assert!(!gop.found_existing);
Ok(())
}
/// Can only be called on the bundler thread.
pub fn get_index(&self, real_source_index: IndexInt) -> Option<usize> {
self.map.get_index_adapted(
&real_source_index,
&Adapter {
source_indices: self.list.items::<"source_index", IndexInt>(),
},
)
}
/// Use this to improve speed of accessing fields at the cost of
/// storing more pointers. Invalidated when input is mutated.
pub fn slice(&self) -> Slice<'_> {
Slice {
list: self.list.slice(),
map: &self.map,
}
}
}
pub struct Slice<'a> {
pub list: multi_array_list::Slice<ServerComponentBoundary>,
pub map: &'a Map,
}
impl<'a> Slice<'a> {
pub fn get_index(&self, real_source_index: IndexInt) -> Option<usize> {
self.map.get_index_adapted(
&real_source_index,
&Adapter {
source_indices: self.list.items::<"source_index", IndexInt>(),
},
)
}
pub fn get_reference_source_index(&self, real_source_index: IndexInt) -> Option<u32> {
let i = self.map.get_index_adapted(
&real_source_index,
&Adapter {
source_indices: self.list.items::<"source_index", IndexInt>(),
},
)?;
// Zig: `bun.unsafeAssert(l.list.capacity > 0)` — optimization hint for
// `MultiArrayList.Slice.items`. The Rust `items()` already short-circuits
// on `capacity == 0`, so the assert is dropped.
Some(self.list.items::<"reference_source_index", IndexInt>()[i])
}
pub fn bit_set(
&self,
input_file_count: usize,
) -> Result<DynamicBitSetUnmanaged, bun_alloc::AllocError> {
let mut scb_bitset = DynamicBitSetUnmanaged::init_empty(input_file_count)?;
for &source_index in self.list.items::<"source_index", IndexInt>() {
scb_bitset.set(source_index as usize);
}
Ok(scb_bitset)
}
}
// PORT NOTE: Zig stored the full `MultiArrayList.Slice` and called
// `.items(.source_index)` on each compare. The Rust `Slice<T>` is not `Copy`,
// so we cache just the `source_index` column the adapter actually needs.
pub(crate) struct Adapter<'a> {
pub source_indices: &'a [IndexInt],
}
impl<'a> ArrayHashAdapter<IndexInt, ()> for Adapter<'a> {
#[inline]
fn hash(&self, key: &IndexInt) -> u32 {
bun_wyhash::hash_int(*key)
}
#[inline]
fn eql(&self, a: &IndexInt, _b: &(), b_index: usize) -> bool {
*a == self.source_indices[b_index]
}
}
// ported from: src/js_parser/ast/ServerComponentBoundary.zig