use vize_carton::CompactString;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct ProviderId(u32);
impl ProviderId {
#[inline(always)]
pub const fn new(id: u32) -> Self {
Self(id)
}
#[inline(always)]
pub const fn as_u32(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ProvideKey {
String(CompactString),
Symbol(CompactString),
}
#[derive(Debug, Clone)]
pub struct ProvideEntry {
pub id: ProviderId,
pub key: ProvideKey,
pub value: CompactString,
pub value_type: Option<CompactString>,
pub from_composable: Option<CompactString>,
pub start: u32,
pub end: u32,
}
#[derive(Debug, Clone, Default)]
pub enum InjectPattern {
#[default]
Simple,
ObjectDestructure(Vec<CompactString>),
ArrayDestructure(Vec<CompactString>),
IndirectDestructure {
inject_var: CompactString,
props: Vec<CompactString>,
offset: u32,
},
}
#[derive(Debug, Clone)]
pub struct InjectEntry {
pub key: ProvideKey,
pub local_name: CompactString,
pub default_value: Option<CompactString>,
pub expected_type: Option<CompactString>,
pub pattern: InjectPattern,
pub from_composable: Option<CompactString>,
pub start: u32,
pub end: u32,
}
#[derive(Debug, Clone)]
pub struct ComposableCall {
pub name: CompactString,
pub source: CompactString,
pub local_name: Option<CompactString>,
pub uses_provide: bool,
pub uses_inject: bool,
pub uses_reactivity: bool,
pub start: u32,
pub end: u32,
}
#[derive(Debug, Default)]
pub struct ProvideInjectTracker {
provides: Vec<ProvideEntry>,
injects: Vec<InjectEntry>,
composables: Vec<ComposableCall>,
next_id: u32,
}
impl ProvideInjectTracker {
#[inline]
pub fn new() -> Self {
Self::default()
}
pub fn add_provide(
&mut self,
key: ProvideKey,
value: CompactString,
value_type: Option<CompactString>,
from_composable: Option<CompactString>,
start: u32,
end: u32,
) -> ProviderId {
let id = ProviderId::new(self.next_id);
self.next_id += 1;
self.provides.push(ProvideEntry {
id,
key,
value,
value_type,
from_composable,
start,
end,
});
id
}
#[allow(clippy::too_many_arguments)]
pub fn add_inject(
&mut self,
key: ProvideKey,
local_name: CompactString,
default_value: Option<CompactString>,
expected_type: Option<CompactString>,
pattern: InjectPattern,
from_composable: Option<CompactString>,
start: u32,
end: u32,
) {
self.injects.push(InjectEntry {
key,
local_name,
default_value,
expected_type,
pattern,
from_composable,
start,
end,
});
}
#[allow(clippy::too_many_arguments)]
pub fn add_composable(
&mut self,
name: CompactString,
source: CompactString,
local_name: Option<CompactString>,
uses_provide: bool,
uses_inject: bool,
uses_reactivity: bool,
start: u32,
end: u32,
) {
self.composables.push(ComposableCall {
name,
source,
local_name,
uses_provide,
uses_inject,
uses_reactivity,
start,
end,
});
}
#[inline]
pub fn composables(&self) -> &[ComposableCall] {
&self.composables
}
#[inline]
pub fn has_destructured_injects(&self) -> bool {
self.injects
.iter()
.any(|i| !matches!(i.pattern, InjectPattern::Simple))
}
pub fn destructured_injects(&self) -> impl Iterator<Item = &InjectEntry> {
self.injects
.iter()
.filter(|i| !matches!(i.pattern, InjectPattern::Simple))
}
#[inline]
pub fn provides(&self) -> &[ProvideEntry] {
&self.provides
}
#[inline]
pub fn injects(&self) -> &[InjectEntry] {
&self.injects
}
pub fn add_indirect_destructure(
&mut self,
inject_var: CompactString,
props: Vec<CompactString>,
offset: u32,
) {
for inject in &mut self.injects {
if inject.local_name == inject_var {
inject.pattern = InjectPattern::IndirectDestructure {
inject_var: inject_var.clone(),
props,
offset,
};
return;
}
}
}
}
#[cfg(test)]
mod tests {
use super::{InjectPattern, ProvideInjectTracker, ProvideKey};
use vize_carton::CompactString;
#[test]
fn test_provide_inject() {
let mut tracker = ProvideInjectTracker::new();
tracker.add_provide(
ProvideKey::String(CompactString::new("theme")),
CompactString::new("dark"),
Some(CompactString::new("string")),
None,
0,
20,
);
tracker.add_inject(
ProvideKey::String(CompactString::new("theme")),
CompactString::new("theme"),
Some(CompactString::new("'light'")),
Some(CompactString::new("string")),
InjectPattern::Simple,
None,
30,
50,
);
assert_eq!(tracker.provides().len(), 1);
assert_eq!(tracker.injects().len(), 1);
}
#[test]
fn test_composable_tracking() {
let mut tracker = ProvideInjectTracker::new();
tracker.add_composable(
CompactString::new("useTheme"),
CompactString::new("./composables/theme"),
Some(CompactString::new("theme")),
true,
false,
true,
0,
20,
);
assert_eq!(tracker.composables().len(), 1);
assert!(tracker.composables()[0].uses_provide);
assert!(tracker.composables()[0].uses_reactivity);
}
}