use std::sync::atomic::AtomicU32; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FileId { id: u32, } impl FileId { pub fn new() -> Self { static GEN: AtomicU32 = AtomicU32::new(0); Self { id: GEN.fetch_add(1, std::sync::atomic::Ordering::SeqCst), } } pub fn from(self, start: u32) -> SpanFrom { SpanFrom::new(self, start) } pub fn span(self, start: u32, end: u32) -> Span { Span::new(self, start, end) } } #[derive(Copy, Clone)] pub struct SpanFrom { pub file: FileId, pub start: u32, } impl SpanFrom { pub fn new(file: FileId, start: u32) -> Self { Self { file, start } } pub fn to(self, end: u32) -> Span { Span::new(self.file, self.start, end) } pub fn with_len(self, len: u32) -> Span { self.to(self.start + len) } } #[derive(Copy, Clone, PartialEq, Eq)] pub struct Span { pub file: FileId, pub start: u32, pub end: u32, } /// manual implementation of PartialOrd to ensure shorter Spans are first impl PartialOrd for Span { fn partial_cmp(&self, other: &Self) -> Option { match self.file.partial_cmp(&other.file) { Some(core::cmp::Ordering::Equal) => {} ord => return ord, } match self.start.partial_cmp(&other.start) { Some(core::cmp::Ordering::Equal) => {} ord => return ord, } other.end.partial_cmp(&self.end) } } /// manual implementation of Ord to ensure shorter Spans are first impl Ord for Span { fn cmp(&self, other: &Self) -> std::cmp::Ordering { match self.file.cmp(&other.file) { core::cmp::Ordering::Equal => {} ord => return ord, } match self.start.cmp(&other.start) { core::cmp::Ordering::Equal => {} ord => return ord, } other.end.cmp(&self.end) } } impl Span { pub fn new(file: FileId, start: u32, end: u32) -> Self { Self { file, start, end } } }