mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(span): port over more methods from TextRange (#3592)
Ports over more utility methods from `TextRange`, as per feedback in [this comment](https://github.com/oxc-project/oxc/pull/3589#discussion_r1632169132) from #3589
This commit is contained in:
parent
f0b689d115
commit
129f91e444
2 changed files with 187 additions and 6 deletions
|
|
@ -1,10 +1,16 @@
|
|||
use std::{borrow::Borrow, fmt, hash, ops::Deref};
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
fmt, hash,
|
||||
ops::{Deref, Index},
|
||||
};
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
use compact_str::CompactString;
|
||||
|
||||
use crate::Span;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = r#"
|
||||
|
|
@ -12,7 +18,7 @@ export type Atom = string;
|
|||
export type CompactStr = string;
|
||||
"#;
|
||||
|
||||
/// Maximum length for inline string, which can be created with `CompactStr::new_const`.
|
||||
/// Maximum length for inline string, which can be created with [`CompactStr::new_const`].
|
||||
pub const MAX_INLINE_LEN: usize = 16;
|
||||
|
||||
/// An inlinable string for oxc_allocator.
|
||||
|
|
@ -261,6 +267,14 @@ impl PartialEq<CompactStr> for &str {
|
|||
}
|
||||
}
|
||||
|
||||
impl Index<Span> for CompactStr {
|
||||
type Output = str;
|
||||
|
||||
fn index(&self, index: Span) -> &Self::Output {
|
||||
&self.0[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl hash::Hash for CompactStr {
|
||||
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
|
||||
self.as_str().hash(hasher);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
// Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
|
||||
// Silence erroneous warnings from Rust Analyzer for `#[derive(Tsify)]`
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::{
|
||||
hash::{Hash, Hasher},
|
||||
ops::{Index, IndexMut, Range},
|
||||
};
|
||||
|
||||
use miette::{LabeledSpan, SourceOffset, SourceSpan};
|
||||
|
||||
|
|
@ -56,6 +59,35 @@ impl Span {
|
|||
Self { start, end }
|
||||
}
|
||||
|
||||
/// Create a new empty [`Span`] that starts and ends at an offset position.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use oxc_span::Span;
|
||||
///
|
||||
/// let fifth = Span::empty(5);
|
||||
/// assert!(fifth.is_empty());
|
||||
/// assert_eq!(fifth, Span::sized(5, 0));
|
||||
/// assert_eq!(fifth, Span::new(5, 5));
|
||||
/// ```
|
||||
pub fn empty(at: u32) -> Self {
|
||||
Self { start: at, end: at }
|
||||
}
|
||||
|
||||
/// Create a new [`Span`] starting at `start` and covering `size` characters.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use oxc_span::Span;
|
||||
///
|
||||
/// let span = Span::sized(2, 4);
|
||||
/// assert_eq!(span.size(), 4);
|
||||
/// assert_eq!(span, Span::new(2, 6));
|
||||
/// ```
|
||||
pub const fn sized(start: u32, size: u32) -> Self {
|
||||
Self::new(start, start + size)
|
||||
}
|
||||
|
||||
/// Get the number of characters covered by the [`Span`].
|
||||
///
|
||||
/// # Example
|
||||
|
|
@ -66,7 +98,7 @@ impl Span {
|
|||
/// assert_eq!(Span::new(0, 5).size(), 5);
|
||||
/// assert_eq!(Span::new(5, 10).size(), 5);
|
||||
/// ```
|
||||
pub fn size(&self) -> u32 {
|
||||
pub const fn size(&self) -> u32 {
|
||||
debug_assert!(self.start <= self.end);
|
||||
self.end - self.start
|
||||
}
|
||||
|
|
@ -81,7 +113,7 @@ impl Span {
|
|||
/// assert!(Span::new(5, 5).is_empty());
|
||||
/// assert!(!Span::new(0, 5).is_empty());
|
||||
/// ```
|
||||
pub fn is_empty(&self) -> bool {
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
debug_assert!(self.start <= self.end);
|
||||
self.start == self.end
|
||||
}
|
||||
|
|
@ -102,6 +134,119 @@ impl Span {
|
|||
Self::new(self.start.min(other.start), self.end.max(other.end))
|
||||
}
|
||||
|
||||
/// Create a [`Span`] that has its start position moved to the left by
|
||||
/// `offset` bytes.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use oxc_span::Span;
|
||||
///
|
||||
/// let a = Span::new(5, 10);
|
||||
/// assert_eq!(a.expand_left(5), Span::new(0, 10));
|
||||
/// ```
|
||||
///
|
||||
/// ## Bounds
|
||||
///
|
||||
/// The leftmost bound of the span is clamped to 0. It is safe to call this
|
||||
/// method with a value larger than the start position.
|
||||
///
|
||||
/// ```
|
||||
/// use oxc_span::Span;
|
||||
///
|
||||
/// let a = Span::new(0, 5);
|
||||
/// assert_eq!(a.expand_left(5), Span::new(0, 5));
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub const fn expand_left(self, offset: u32) -> Self {
|
||||
Self::new(self.start.saturating_sub(offset), self.end)
|
||||
}
|
||||
|
||||
/// Create a [`Span`] that has its start position moved to the right by
|
||||
/// `offset` bytes.
|
||||
///
|
||||
/// It is a logical error to shrink the start of the [`Span`] past its end
|
||||
/// position.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use oxc_span::Span;
|
||||
///
|
||||
/// let a = Span::new(5, 10);
|
||||
/// let shrunk = a.shrink_left(5);
|
||||
/// assert_eq!(shrunk, Span::new(10, 10));
|
||||
///
|
||||
/// // Shrinking past the end of the span is a logical error that will panic
|
||||
/// // in debug builds.
|
||||
/// std::panic::catch_unwind(|| {
|
||||
/// shrunk.shrink_left(5);
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
#[must_use]
|
||||
pub const fn shrink_left(self, offset: u32) -> Self {
|
||||
let start = self.start.saturating_add(offset);
|
||||
debug_assert!(start <= self.end);
|
||||
Self::new(self.start.saturating_add(offset), self.end)
|
||||
}
|
||||
|
||||
/// Create a [`Span`] that has its end position moved to the right by
|
||||
/// `offset` bytes.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use oxc_span::Span;
|
||||
///
|
||||
/// let a = Span::new(5, 10);
|
||||
/// assert_eq!(a.expand_right(5), Span::new(5, 15));
|
||||
/// ```
|
||||
///
|
||||
/// ## Bounds
|
||||
///
|
||||
/// The rightmost bound of the span is clamped to `u32::MAX`. It is safe to
|
||||
/// call this method with a value larger than the end position.
|
||||
///
|
||||
/// ```
|
||||
/// use oxc_span::Span;
|
||||
///
|
||||
/// let a = Span::new(0, u32::MAX);
|
||||
/// assert_eq!(a.expand_right(5), Span::new(0, u32::MAX));
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub const fn expand_right(self, offset: u32) -> Self {
|
||||
Self::new(self.start, self.end.saturating_add(offset))
|
||||
}
|
||||
|
||||
/// Create a [`Span`] that has its end position moved to the left by
|
||||
/// `offset` bytes.
|
||||
///
|
||||
/// It is a logical error to shrink the end of the [`Span`] past its start
|
||||
/// position.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use oxc_span::Span;
|
||||
///
|
||||
/// let a = Span::new(5, 10);
|
||||
/// let shrunk = a.shrink_right(5);
|
||||
/// assert_eq!(shrunk, Span::new(5, 5));
|
||||
///
|
||||
/// // Shrinking past the start of the span is a logical error that will panic
|
||||
/// // in debug builds.
|
||||
/// std::panic::catch_unwind(|| {
|
||||
/// shrunk.shrink_right(5);
|
||||
/// });
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub const fn shrink_right(self, offset: u32) -> Self {
|
||||
let end = self.end.saturating_sub(offset);
|
||||
debug_assert!(self.start <= end);
|
||||
Self::new(self.start, end)
|
||||
}
|
||||
|
||||
/// Get a snippet of text from a source string that the [`Span`] covers.
|
||||
///
|
||||
/// # Example
|
||||
|
|
@ -118,6 +263,28 @@ impl Span {
|
|||
}
|
||||
}
|
||||
|
||||
impl Index<Span> for str {
|
||||
type Output = str;
|
||||
#[inline]
|
||||
fn index(&self, index: Span) -> &Self::Output {
|
||||
&self[index.start as usize..index.end as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<Span> for str {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: Span) -> &mut Self::Output {
|
||||
&mut self[index.start as usize..index.end as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Range<u32>> for Span {
|
||||
#[inline]
|
||||
fn from(range: Range<u32>) -> Self {
|
||||
Self::new(range.start, range.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Span {
|
||||
fn hash<H: Hasher>(&self, _state: &mut H) {
|
||||
// hash to nothing so all ast spans can be comparable with hash
|
||||
|
|
|
|||
Loading…
Reference in a new issue