use alloc::vec::Vec;
use vize_l0::{Span, String};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ScopeTag(u32);
impl ScopeTag {
#[inline]
#[must_use]
pub const fn from_index(index: u32) -> Self {
Self(index)
}
#[inline]
#[must_use]
pub const fn index(self) -> u32 {
self.0
}
}
impl core::fmt::Display for ScopeTag {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "#{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ScopeOrigin {
Authored {
span: Span,
},
Synthesized {
rule: String,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopeBinding {
pub name: String,
pub origin: ScopeOrigin,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopeFacts {
pub tag: ScopeTag,
pub bindings: Vec<ScopeBinding>,
}
const _: () = {
const fn assert_owned<T: 'static>() {}
assert_owned::<ScopeFacts>();
assert_owned::<ScopeBinding>();
assert_owned::<ScopeOrigin>();
};
const _: () = assert!(core::mem::size_of::<ScopeTag>() == 4);
#[cfg(target_pointer_width = "64")]
const _: () = {
assert!(core::mem::size_of::<ScopeOrigin>() == 24);
assert!(core::mem::size_of::<ScopeBinding>() == 48);
assert!(core::mem::size_of::<ScopeFacts>() == 32);
};
#[cfg(test)]
mod tests {
use super::{ScopeBinding, ScopeFacts, ScopeOrigin, ScopeTag};
use alloc::vec;
use vize_l0::{Span, String, cstr};
#[test]
fn tags_mint_densely_and_order_by_index() {
let first = ScopeTag::from_index(0);
let second = ScopeTag::from_index(1);
assert_eq!(first.index(), 0);
assert_eq!(second.index(), 1);
assert!(first < second);
assert_eq!(cstr!("{first}").as_str(), "#0");
}
#[test]
fn a_synthesized_name_never_equals_an_authored_one() {
let authored = ScopeBinding {
name: String::from("item"),
origin: ScopeOrigin::Authored {
span: Span::new(14, 18),
},
};
let synthesized = ScopeBinding {
name: String::from("item"),
origin: ScopeOrigin::Synthesized {
rule: String::from("normalize.slot-props"),
},
};
assert_eq!(authored.name, synthesized.name);
assert_ne!(authored, synthesized);
}
#[test]
fn facts_hold_bindings_in_position_order() {
let facts = ScopeFacts {
tag: ScopeTag::from_index(2),
bindings: vec![
ScopeBinding {
name: String::from("item"),
origin: ScopeOrigin::Authored {
span: Span::new(10, 14),
},
},
ScopeBinding {
name: String::from("index"),
origin: ScopeOrigin::Authored {
span: Span::new(16, 21),
},
},
],
};
assert_eq!(facts.tag, ScopeTag::from_index(2));
assert_eq!(facts.bindings.len(), 2);
assert_eq!(facts.bindings[0].name.as_str(), "item");
assert_eq!(facts.bindings[1].name.as_str(), "index");
}
}