> From for Context {
fn from(path: P) -> Self {
Self(path.into())
}
}
impl Display for Context {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
/// An interned path.
///
/// This is interned as a string slice ([`SymbolId`]),
/// not a `PathBuf`.
/// Consequently,
/// it is not an `OsStr`.
///
/// This newtype emphasizes that it differs from typical symbol usage,
/// especially given that it'll always use the 16-bit interner,
/// _not_ necessarily whatever global interner is used for all other
/// symbols.
/// In the future,
/// these may be interned separately.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct PathIndex(PathSymbolId);
impl From for PathIndex {
fn from(sym: PathSymbolId) -> Self {
Self(sym)
}
}
impl Display for PathIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
/// A closed interval (range of values including its endpoints) representing
/// source bytes associated with a token.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct ClosedByteInterval(pub T, pub T)
where
T: Copy + PartialOrd;
impl From<(T, T)> for ClosedByteInterval {
/// Convert a tuple into a closed byte interval where the first index
/// represents the start of the interval and the second index the
/// end.
///
/// Panics
/// ======
/// The second value must be ≥ the first.
fn from(src: (T, T)) -> Self {
assert!(src.1 >= src.0);
Self(src.0, src.1)
}
}
assert_eq_size!(ClosedByteInterval, u64);
#[cfg(test)]
mod test {
use super::*;
use crate::sym::GlobalSymbolIntern;
// Little endian check.
//
// This ensures that the byte ordering is as expected,
// otherwise the resulting integer will not have the properties we
// require for sorting and comparison.
#[cfg(target_endian = "little")]
#[test]
fn span_pack_le() {
let span =
Span::new(0xA3A2A1A0, 0xB1B0, SymbolId::test_from_int(0xC1C0));
assert_eq!(
0xC1C0_A3A2A1A0_B1B0,
// ^ ^ ^
// ctx offset len
span.as_u64(),
"endianness check failed: {:X?}",
span.as_u64()
);
}
#[cfg(target_endian = "big")]
#[test]
fn span_pack_be_not_supported() {
panic!("Big-endian systems are not currently supported");
}
// The tests that follow are corollaries of the above, but the below
// tests do test that the implementations function as intended.
#[test]
fn span_at_later_offset_in_same_context_compares_greater() {
let ctx = "imaginary".intern();
let first = Span::new(10, 5, ctx);
let second = Span::new(20, 5, ctx);
// These two assertions must be identical.
assert!(second > first);
assert!(second.as_u64() > first.as_u64());
}
#[test]
fn spans_order_by_context_start_and_len() {
let ctxa = "context a".intern();
let ctxb = "context b".intern();
// Sanity check, otherwise this test won't work as expected.
assert!(ctxa < ctxb);
let sa1 = Span::new(10, 1, ctxa);
let sa2 = Span::new(22, 1, ctxa);
let sa3 = Span::new(35, 1, ctxa);
let sb1 = Span::new(11, 1, ctxb);
let sb2 = Span::new(20, 1, ctxb);
let sb3 = Span::new(33, 1, ctxb);
let mut spans = vec![sa3, sb2, sb1, sa2, sa1, sb3];
spans.sort();
assert_eq!(spans, vec![sa1, sa2, sa3, sb1, sb2, sb3]);
}
#[test]
pub fn retrieve_span_components() {
let ctx: Context = "foo".intern().into();
let offset = 100;
let len = 50;
let span = Span::new(offset, len, ctx);
assert_eq!((offset, len, ctx), (span.offset(), span.len(), span.ctx()));
}
#[test]
pub fn span_offset_add() {
let ctx: Context = "addtest".intern().into();
let offset = 10;
let len = 5;
let span = Span::new(offset, len, ctx);
// Successful add.
assert_eq!(
span.offset_add(10),
Some(Span {
offset: offset + 10,
len,
ctx
})
);
// Fail, do not wrap.
assert_eq!(span.offset_add(global::SourceFileSize::MAX), None);
}
#[test]
pub fn span_into_twospan() {
let ctx: Context = "foo".intern().into();
let span = Span::new(10, 50, ctx);
assert_eq!((span, span), span.into());
}
#[test]
pub fn span_endpoints() {
let ctx: Context = "end".intern().into();
let span = Span::new(10, 20, ctx);
let (start, end) = span.endpoints();
assert_eq!(start, Span::new(10, 0, ctx));
assert_eq!(end, Some(Span::new(30, 0, ctx)));
}
}