use std::{borrow::Cow, hash::Hash, sync::atomic::AtomicU32};
use either::Either;
use rspack_cacheable::{
cacheable,
with::{AsPreset, AsVec},
};
use rspack_util::{atom::Atom, json_stringify, ryu_js};
use rustc_hash::FxHashSet as HashSet;
use crate::{DependencyId, property_access};
pub static NEXT_EXPORTS_INFO_UKEY: AtomicU32 = AtomicU32::new(0);
pub static NEXT_EXPORT_INFO_UKEY: AtomicU32 = AtomicU32::new(0);
#[derive(Debug, Clone, Hash)]
pub struct ExportInfoTargetValue {
pub dependency: Option<DependencyId>,
pub export: Option<Vec<Atom>>,
pub priority: u8,
}
pub enum ProvidedExports {
Unknown,
ProvidedAll,
ProvidedNames(Vec<Atom>),
}
pub enum UsedExports {
Unknown,
UsedNamespace(bool),
UsedNames(Vec<Atom>),
}
#[cacheable]
#[derive(Debug, Clone)]
pub enum EvaluatedInlinableValue {
Null,
Undefined,
Boolean(bool),
Number(f64),
String(#[cacheable(with=AsPreset)] Atom),
}
impl Hash for EvaluatedInlinableValue {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {
EvaluatedInlinableValue::Boolean(v) => {
v.hash(state);
}
EvaluatedInlinableValue::Number(v) => {
v.to_bits().hash(state);
}
EvaluatedInlinableValue::String(atom) => {
atom.hash(state);
}
_ => {}
}
}
}
impl EvaluatedInlinableValue {
pub const SHORT_SIZE: usize = 6;
pub fn new_null() -> Self {
Self::Null
}
pub fn new_undefined() -> Self {
Self::Undefined
}
pub fn new_boolean(v: bool) -> Self {
Self::Boolean(v)
}
pub fn new_number(v: f64) -> Self {
Self::Number(v)
}
pub fn new_string(v: Atom) -> Self {
Self::String(v)
}
pub fn render(&self, comment: &str) -> String {
let s: Cow<str> = match self {
Self::Null => "null".into(),
Self::Undefined => "undefined".into(),
Self::Boolean(v) => if *v { "true" } else { "false" }.into(),
Self::Number(v) => {
let mut buf = ryu_js::Buffer::new();
buf.format(*v).to_string().into()
}
Self::String(v) => json_stringify(v.as_str()).into(),
};
format!("({comment}{s})")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CanInlineUse {
HasInfo,
Yes,
No,
}
#[derive(Debug, Clone, Hash)]
pub enum UsedNameItem {
Str(Atom),
Inlined(EvaluatedInlinableValue),
}
#[derive(Debug, Clone)]
pub struct InlinedUsedName {
value: EvaluatedInlinableValue,
suffix: Vec<Atom>,
}
impl InlinedUsedName {
pub fn new(value: EvaluatedInlinableValue) -> Self {
Self {
value,
suffix: Vec::new(),
}
}
pub fn render(&self, comment: &str) -> String {
let mut inlined = self.value.render(comment);
inlined.push_str(&property_access(&self.suffix, 0));
inlined
}
pub fn inlined_value(&self) -> &EvaluatedInlinableValue {
&self.value
}
pub fn suffix_ids(&self) -> &[Atom] {
&self.suffix
}
}
#[derive(Debug, Clone)]
pub enum UsedName {
Normal(Vec<Atom>),
Inlined(InlinedUsedName),
}
impl UsedName {
pub fn append(&mut self, item: impl IntoIterator<Item = Atom>) {
match self {
UsedName::Normal(vec) => vec.extend(item),
UsedName::Inlined(inlined) => inlined.suffix.extend(item),
}
}
}
#[derive(Debug, Hash, Clone, Copy)]
pub enum ExportProvided {
Provided,
NotProvided,
Unknown,
}
#[derive(Debug, Hash, PartialEq, Eq, Default, Clone)]
pub struct UsageKey(pub Vec<Either<Box<UsageKey>, UsageState>>);
impl UsageKey {
pub fn add(&mut self, value: Either<Box<UsageKey>, UsageState>) {
self.0.push(value);
}
}
pub type UsageFilterFnTy<T> = Box<dyn Fn(&T) -> bool>;
#[derive(Debug, PartialEq, Copy, Clone, Default, Hash, PartialOrd, Ord, Eq)]
pub enum UsageState {
Unused = 0,
OnlyPropertiesUsed = 1,
NoInfo = 2,
#[default]
Unknown = 3,
Used = 4,
}
#[cacheable]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UsedByExports {
pub condition: UsedByExportsCondition,
#[cacheable(with=AsVec)]
pub deferred_pure_checks: Vec<UsedByExportsDeferredPureCheck>,
}
impl UsedByExports {
pub fn set(exports: HashSet<Atom>) -> Self {
Self {
condition: UsedByExportsCondition::Set(exports),
deferred_pure_checks: Vec::new(),
}
}
pub fn bool(used: bool) -> Self {
Self {
condition: UsedByExportsCondition::Bool(used),
deferred_pure_checks: Vec::new(),
}
}
pub fn with_deferred_pure_checks(
mut self,
deferred_pure_checks: Vec<UsedByExportsDeferredPureCheck>,
) -> Self {
self.deferred_pure_checks = deferred_pure_checks;
self
}
}
#[cacheable]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UsedByExportsCondition {
Set(#[cacheable(with=AsVec<AsPreset>)] HashSet<Atom>),
Bool(bool),
}
#[cacheable]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UsedByExportsDeferredPureCheck {
pub dep_id: DependencyId,
#[cacheable(with=AsPreset)]
pub atom: Atom,
}