From 5595c60d510239b3e779bf2a76d86324360da114 Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Sun, 8 Sep 2024 13:54:08 +0100 Subject: [PATCH] refactor(span): move `CompactStr` into separate file --- crates/oxc_span/src/atom.rs | 260 +--------------------------- crates/oxc_span/src/compact_str.rs | 269 +++++++++++++++++++++++++++++ crates/oxc_span/src/lib.rs | 4 +- 3 files changed, 275 insertions(+), 258 deletions(-) create mode 100644 crates/oxc_span/src/compact_str.rs diff --git a/crates/oxc_span/src/atom.rs b/crates/oxc_span/src/atom.rs index 213dbd614f10ec..01e6ca2c6c1814 100644 --- a/crates/oxc_span/src/atom.rs +++ b/crates/oxc_span/src/atom.rs @@ -1,26 +1,21 @@ use std::{ borrow::{Borrow, Cow}, fmt, hash, - ops::{Deref, Index}, + ops::Deref, }; -use compact_str::CompactString; use oxc_allocator::{Allocator, CloneIn, FromIn}; #[cfg(feature = "serialize")] -use serde::{Serialize, Serializer}; +use serde::Serialize; -use crate::{cmp::ContentEq, hash::ContentHash, Span}; +use crate::{cmp::ContentEq, hash::ContentHash, CompactStr}; #[cfg(feature = "serialize")] #[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)] const TS_APPEND_CONTENT: &'static str = r#" export type Atom = string; -export type CompactStr = string; "#; -/// 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. /// /// Use [CompactStr] with [Atom::to_compact_str] or [Atom::into_compact_str] for @@ -203,252 +198,3 @@ impl<'a> fmt::Display for Atom<'a> { fmt::Display::fmt(self.as_str(), f) } } - -/// Lifetimeless version of [`Atom<'_>`] which owns its own string data allocation. -/// -/// [`CompactStr`] is immutable. Use [`CompactStr::into_string`] for a mutable -/// [`String`]. -/// -/// Currently implemented as just a wrapper around [`compact_str::CompactString`], -/// but will be reduced in size with a custom implementation later. -#[derive(Clone, Eq, PartialOrd, Ord)] -#[cfg_attr(feature = "serialize", derive(serde::Deserialize))] -pub struct CompactStr(CompactString); - -impl CompactStr { - /// Create a new [`CompactStr`]. - /// - /// If `&str` is `'static` and no more than [`MAX_INLINE_LEN`] bytes, - /// prefer [`CompactStr::new_const`] which creates the [`CompactStr`] at - /// compile time. - /// - /// # Examples - /// ``` - /// let s = CompactStr::new("long string which can't use new_const for"); - /// ``` - #[inline] - pub fn new(s: &str) -> Self { - Self(CompactString::new(s)) - } - - /// Create a [`CompactStr`] at compile time. - /// - /// String must be no longer than [`MAX_INLINE_LEN`] bytes. - /// - /// Prefer this over [`CompactStr::new`] or [`CompactStr::from`] where - /// string is `'static` and not longer than [`MAX_INLINE_LEN`] bytes. - /// - /// # Panics - /// Panics if string is longer than [`MAX_INLINE_LEN`] bytes. - /// - /// # Examples - /// ``` - /// const S: CompactStr = CompactStr::new_const("short"); - /// ``` - #[inline] - pub const fn new_const(s: &'static str) -> Self { - assert!(s.len() <= MAX_INLINE_LEN); - Self(CompactString::const_new(s)) - } - - /// Get string content as a `&str` slice. - #[inline] - pub fn as_str(&self) -> &str { - self.0.as_str() - } - - /// Convert a [`CompactStr`] into a [`String`]. - #[inline] - pub fn into_string(self) -> String { - self.0.into_string() - } - - /// Convert a [`CompactStr`] into a [`CompactString`]. - #[inline] - pub fn into_compact_string(self) -> CompactString { - self.0 - } - - /// Get length of [`CompactStr`]. - /// - /// # Examples - /// ``` - /// use oxc_span::CompactStr; - /// - /// assert_eq!(CompactStr::new("").len(), 0); - /// assert_eq!(CompactStr::new_const("").len(), 0); - /// assert_eq!(CompactStr::new("hello").len(), 5); - /// ``` - #[inline] - pub fn len(&self) -> usize { - self.0.len() - } - - /// Check if a [`CompactStr`] is empty (0 length). - /// - /// # Examples - /// ``` - /// use oxc_span::CompactStr; - /// - /// assert!(CompactStr::new("").is_empty()); - /// assert!(!CompactStr::new("hello").is_empty()); - /// ``` - #[inline] - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -impl From<&str> for CompactStr { - fn from(s: &str) -> Self { - Self(CompactString::from(s)) - } -} - -impl From for CompactStr { - fn from(s: String) -> Self { - Self(CompactString::from(s)) - } -} - -impl<'s> From<&'s CompactStr> for Cow<'s, str> { - fn from(value: &'s CompactStr) -> Self { - Self::Borrowed(value.as_str()) - } -} - -impl From for Cow<'_, str> { - fn from(value: CompactStr) -> Self { - value.0.into() - } -} -impl From> for CompactStr { - fn from(value: Cow<'_, str>) -> Self { - match value { - Cow::Borrowed(s) => CompactStr::new(s), - Cow::Owned(s) => CompactStr::from(s), - } - } -} - -impl Deref for CompactStr { - type Target = str; - - fn deref(&self) -> &Self::Target { - self.as_str() - } -} - -impl AsRef for CompactStr { - fn as_ref(&self) -> &str { - self.as_str() - } -} - -impl Borrow for CompactStr { - fn borrow(&self) -> &str { - self.as_str() - } -} - -impl> PartialEq for CompactStr { - fn eq(&self, other: &T) -> bool { - self.as_str() == other.as_ref() - } -} - -impl PartialEq for &str { - fn eq(&self, other: &CompactStr) -> bool { - *self == other.as_str() - } -} - -impl PartialEq for str { - fn eq(&self, other: &CompactStr) -> bool { - self == other.as_str() - } -} - -impl PartialEq for CompactStr { - fn eq(&self, other: &str) -> bool { - self.as_str() == other - } -} - -impl PartialEq for Cow<'_, str> { - fn eq(&self, other: &CompactStr) -> bool { - self.as_ref() == other.as_str() - } -} - -impl Index for CompactStr { - type Output = str; - - fn index(&self, index: Span) -> &Self::Output { - &self.0[index] - } -} - -impl hash::Hash for CompactStr { - fn hash(&self, hasher: &mut H) { - self.as_str().hash(hasher); - } -} - -impl fmt::Debug for CompactStr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self.as_str(), f) - } -} - -impl fmt::Display for CompactStr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.as_str(), f) - } -} - -#[cfg(feature = "serialize")] -impl Serialize for CompactStr { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(self.as_str()) - } -} - -#[cfg(feature = "schemars")] -impl schemars::JsonSchema for CompactStr { - fn is_referenceable() -> bool { - false - } - - fn schema_name() -> std::string::String { - "String".to_string() - } - - fn schema_id() -> Cow<'static, str> { - Cow::Borrowed("String") - } - - fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { - <&str>::json_schema(gen) - } -} - -#[cfg(test)] -mod test { - use compact_str::CompactString; - - use super::CompactStr; - - #[test] - fn test_compactstr_eq() { - let foo = CompactStr::new("foo"); - assert_eq!(foo, "foo"); - assert_eq!(&foo, "foo"); - assert_eq!("foo", foo); - assert_eq!("foo", &foo); - assert_eq!(foo.into_compact_string(), CompactString::new("foo")); - } -} diff --git a/crates/oxc_span/src/compact_str.rs b/crates/oxc_span/src/compact_str.rs new file mode 100644 index 00000000000000..2198d333beb313 --- /dev/null +++ b/crates/oxc_span/src/compact_str.rs @@ -0,0 +1,269 @@ +use std::{ + borrow::{Borrow, Cow}, + fmt, hash, + ops::{Deref, Index}, +}; + +use compact_str::CompactString; +#[cfg(feature = "serialize")] +use serde::{Serialize, Serializer}; + +use crate::Span; + +#[cfg(feature = "serialize")] +#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)] +const TS_APPEND_CONTENT: &'static str = r#" +export type Atom = string; +"#; + +/// Maximum length for inline string, which can be created with [`CompactStr::new_const`]. +pub const MAX_INLINE_LEN: usize = 16; + +/// Lifetimeless version of [`Atom<'_>`] which owns its own string data allocation. +/// +/// [`CompactStr`] is immutable. Use [`CompactStr::into_string`] for a mutable +/// [`String`]. +/// +/// Currently implemented as just a wrapper around [`compact_str::CompactString`], +/// but will be reduced in size with a custom implementation later. +#[derive(Clone, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "serialize", derive(serde::Deserialize))] +pub struct CompactStr(CompactString); + +impl CompactStr { + /// Create a new [`CompactStr`]. + /// + /// If `&str` is `'static` and no more than [`MAX_INLINE_LEN`] bytes, + /// prefer [`CompactStr::new_const`] which creates the [`CompactStr`] at + /// compile time. + /// + /// # Examples + /// ``` + /// let s = CompactStr::new("long string which can't use new_const for"); + /// ``` + #[inline] + pub fn new(s: &str) -> Self { + Self(CompactString::new(s)) + } + + /// Create a [`CompactStr`] at compile time. + /// + /// String must be no longer than [`MAX_INLINE_LEN`] bytes. + /// + /// Prefer this over [`CompactStr::new`] or [`CompactStr::from`] where + /// string is `'static` and not longer than [`MAX_INLINE_LEN`] bytes. + /// + /// # Panics + /// Panics if string is longer than [`MAX_INLINE_LEN`] bytes. + /// + /// # Examples + /// ``` + /// const S: CompactStr = CompactStr::new_const("short"); + /// ``` + #[inline] + pub const fn new_const(s: &'static str) -> Self { + assert!(s.len() <= MAX_INLINE_LEN); + Self(CompactString::const_new(s)) + } + + /// Get string content as a `&str` slice. + #[inline] + pub fn as_str(&self) -> &str { + self.0.as_str() + } + + /// Convert a [`CompactStr`] into a [`String`]. + #[inline] + pub fn into_string(self) -> String { + self.0.into_string() + } + + /// Convert a [`CompactStr`] into a [`CompactString`]. + #[inline] + pub fn into_compact_string(self) -> CompactString { + self.0 + } + + /// Get length of [`CompactStr`]. + /// + /// # Examples + /// ``` + /// use oxc_span::CompactStr; + /// + /// assert_eq!(CompactStr::new("").len(), 0); + /// assert_eq!(CompactStr::new_const("").len(), 0); + /// assert_eq!(CompactStr::new("hello").len(), 5); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.0.len() + } + + /// Check if a [`CompactStr`] is empty (0 length). + /// + /// # Examples + /// ``` + /// use oxc_span::CompactStr; + /// + /// assert!(CompactStr::new("").is_empty()); + /// assert!(!CompactStr::new("hello").is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +impl From<&str> for CompactStr { + fn from(s: &str) -> Self { + Self(CompactString::from(s)) + } +} + +impl From for CompactStr { + fn from(s: String) -> Self { + Self(CompactString::from(s)) + } +} + +impl<'s> From<&'s CompactStr> for Cow<'s, str> { + fn from(value: &'s CompactStr) -> Self { + Self::Borrowed(value.as_str()) + } +} + +impl From for Cow<'_, str> { + fn from(value: CompactStr) -> Self { + value.0.into() + } +} +impl From> for CompactStr { + fn from(value: Cow<'_, str>) -> Self { + match value { + Cow::Borrowed(s) => CompactStr::new(s), + Cow::Owned(s) => CompactStr::from(s), + } + } +} + +impl Deref for CompactStr { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.as_str() + } +} + +impl AsRef for CompactStr { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl Borrow for CompactStr { + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl> PartialEq for CompactStr { + fn eq(&self, other: &T) -> bool { + self.as_str() == other.as_ref() + } +} + +impl PartialEq for &str { + fn eq(&self, other: &CompactStr) -> bool { + *self == other.as_str() + } +} + +impl PartialEq for str { + fn eq(&self, other: &CompactStr) -> bool { + self == other.as_str() + } +} + +impl PartialEq for CompactStr { + fn eq(&self, other: &str) -> bool { + self.as_str() == other + } +} + +impl PartialEq for Cow<'_, str> { + fn eq(&self, other: &CompactStr) -> bool { + self.as_ref() == other.as_str() + } +} + +impl Index for CompactStr { + type Output = str; + + fn index(&self, index: Span) -> &Self::Output { + &self.0[index] + } +} + +impl hash::Hash for CompactStr { + fn hash(&self, hasher: &mut H) { + self.as_str().hash(hasher); + } +} + +impl fmt::Debug for CompactStr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_str(), f) + } +} + +impl fmt::Display for CompactStr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_str(), f) + } +} + +#[cfg(feature = "serialize")] +impl Serialize for CompactStr { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self.as_str()) + } +} + +#[cfg(feature = "schemars")] +impl schemars::JsonSchema for CompactStr { + fn is_referenceable() -> bool { + false + } + + fn schema_name() -> std::string::String { + "String".to_string() + } + + fn schema_id() -> Cow<'static, str> { + Cow::Borrowed("String") + } + + fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { + <&str>::json_schema(gen) + } +} + +#[cfg(test)] +mod test { + use compact_str::CompactString; + + use super::CompactStr; + + #[test] + fn test_compactstr_eq() { + let foo = CompactStr::new("foo"); + assert_eq!(foo, "foo"); + assert_eq!(&foo, "foo"); + assert_eq!("foo", foo); + assert_eq!("foo", &foo); + assert_eq!(foo.into_compact_string(), CompactString::new("foo")); + } +} diff --git a/crates/oxc_span/src/lib.rs b/crates/oxc_span/src/lib.rs index 8c1babb1780c87..2e8745f7772b74 100644 --- a/crates/oxc_span/src/lib.rs +++ b/crates/oxc_span/src/lib.rs @@ -3,6 +3,7 @@ //! mod atom; +mod compact_str; mod source_type; mod span; @@ -10,7 +11,8 @@ pub mod cmp; pub mod hash; pub use crate::{ - atom::{Atom, CompactStr, MAX_INLINE_LEN as ATOM_MAX_INLINE_LEN}, + atom::Atom, + compact_str::{CompactStr, MAX_INLINE_LEN as ATOM_MAX_INLINE_LEN}, source_type::{ Language, LanguageVariant, ModuleKind, SourceType, UnknownExtension, VALID_EXTENSIONS, },