diff --git a/crates/oxc_transformer/src/es2017/async_to_generator.rs b/crates/oxc_transformer/src/es2017/async_to_generator.rs index 949aed87c0722..724ca393c46c4 100644 --- a/crates/oxc_transformer/src/es2017/async_to_generator.rs +++ b/crates/oxc_transformer/src/es2017/async_to_generator.rs @@ -53,7 +53,7 @@ use std::{borrow::Cow, mem}; -use oxc_allocator::{Box as ArenaBox, String as ArenaString, TakeIn}; +use oxc_allocator::{Box as ArenaBox, StringBuilder as ArenaStringBuilder, TakeIn}; use oxc_ast::{NONE, ast::*}; use oxc_ast_visit::Visit; use oxc_semantic::{ReferenceFlags, ScopeFlags, ScopeId, SymbolFlags}; @@ -571,7 +571,7 @@ impl<'a, 'ctx> AsyncGeneratorExecutor<'a, 'ctx> { return ctx.ast.atom_from_cow(input); } - let mut name = ArenaString::with_capacity_in(input_str.len() + 1, ctx.ast.allocator); + let mut name = ArenaStringBuilder::with_capacity_in(input_str.len() + 1, ctx.ast.allocator); let mut capitalize_next = false; let mut chars = input_str.chars(); @@ -599,7 +599,7 @@ impl<'a, 'ctx> AsyncGeneratorExecutor<'a, 'ctx> { } if is_reserved_keyword(name.as_str()) { - name.insert(0, '_'); + name.push_ascii_byte_start(b'_'); } Atom::from(name) diff --git a/crates/oxc_transformer/src/jsx/jsx_impl.rs b/crates/oxc_transformer/src/jsx/jsx_impl.rs index a1330c07079ca..d56e45abf0ba0 100644 --- a/crates/oxc_transformer/src/jsx/jsx_impl.rs +++ b/crates/oxc_transformer/src/jsx/jsx_impl.rs @@ -88,7 +88,9 @@ //! //! * Babel plugin implementation: -use oxc_allocator::{Box as ArenaBox, String as ArenaString, TakeIn, Vec as ArenaVec}; +use oxc_allocator::{ + Box as ArenaBox, StringBuilder as ArenaStringBuilder, TakeIn, Vec as ArenaVec, +}; use oxc_ast::{AstBuilder, NONE, ast::*}; use oxc_ecmascript::PropName; use oxc_span::{Atom, SPAN, Span}; @@ -1018,7 +1020,7 @@ impl<'a> JsxImpl<'a, '_> { // didn't contain any HTML entities which needed decoding. // So we can just return the `Atom` that's in `only_line` (without any copying). - let mut acc: Option = None; + let mut acc: Option = None; let mut only_line: Option> = None; let mut first_non_whitespace: Option = Some(0); let mut last_non_whitespace: Option = None; @@ -1057,7 +1059,7 @@ impl<'a> JsxImpl<'a, '_> { fn add_line_of_jsx_text( trimmed_line: Atom<'a>, - acc: &mut Option>, + acc: &mut Option>, only_line: &mut Option>, text_len: usize, ctx: &TraverseCtx<'a>, @@ -1069,7 +1071,7 @@ impl<'a> JsxImpl<'a, '_> { // This is the 2nd line containing text. Previous line did not contain any HTML entities. // Generate an accumulator containing previous line and a trailing space. // Current line will be added to the accumulator after it. - let mut buffer = ArenaString::with_capacity_in(text_len, ctx.ast.allocator); + let mut buffer = ArenaStringBuilder::with_capacity_in(text_len, ctx.ast.allocator); buffer.push_str(only_line.as_str()); buffer.push(' '); *acc = Some(buffer); @@ -1100,7 +1102,7 @@ impl<'a> JsxImpl<'a, '_> { /// Caller can use a slice of the original text, rather than making any copies. fn decode_entities( s: &str, - acc: &mut Option>, + acc: &mut Option>, text_len: usize, ctx: &TraverseCtx<'a>, ) { @@ -1118,7 +1120,7 @@ impl<'a> JsxImpl<'a, '_> { } if let Some(end) = end { let buffer = acc.get_or_insert_with(|| { - ArenaString::with_capacity_in(text_len, ctx.ast.allocator) + ArenaStringBuilder::with_capacity_in(text_len, ctx.ast.allocator) }); buffer.push_str(&s[prev..start]); diff --git a/crates/oxc_transformer/src/jsx/refresh.rs b/crates/oxc_transformer/src/jsx/refresh.rs index 102de59dfe9ee..e4910a3be17d9 100644 --- a/crates/oxc_transformer/src/jsx/refresh.rs +++ b/crates/oxc_transformer/src/jsx/refresh.rs @@ -1,4 +1,4 @@ -use std::{collections::hash_map::Entry, iter}; +use std::{collections::hash_map::Entry, iter, str}; use base64::{ encoded_len as base64_encoded_len, @@ -7,7 +7,9 @@ use base64::{ use rustc_hash::FxHashMap; use sha1::{Digest, Sha1}; -use oxc_allocator::{Address, CloneIn, GetAddress, String as ArenaString, TakeIn, Vec as ArenaVec}; +use oxc_allocator::{ + Address, CloneIn, GetAddress, StringBuilder as ArenaStringBuilder, TakeIn, Vec as ArenaVec, +}; use oxc_ast::{AstBuilder, NONE, ast::*, match_expression}; use oxc_semantic::{Reference, ReferenceFlags, ScopeFlags, ScopeId, SymbolFlags}; use oxc_span::{Atom, GetSpan, SPAN}; @@ -556,12 +558,21 @@ impl<'a> ReactRefresh<'a, '_> { debug_assert_eq!(hash.len(), SHA1_HASH_LEN); // Encode to base64 string directly in arena, without an intermediate string allocation - let mut hashed_key = ArenaVec::from_array_in([0; ENCODED_LEN], ctx.ast.allocator); - let encoded_bytes = BASE64_STANDARD.encode_slice(hash, &mut hashed_key).unwrap(); - debug_assert_eq!(encoded_bytes, ENCODED_LEN); + #[expect(clippy::items_after_statements)] + const ZEROS_STR: &str = { + const ZEROS_BYTES: [u8; ENCODED_LEN] = [0; ENCODED_LEN]; + match str::from_utf8(&ZEROS_BYTES) { + Ok(s) => s, + Err(_) => unreachable!(), + } + }; + + let mut hashed_key = ArenaStringBuilder::from_str_in(ZEROS_STR, ctx.ast.allocator); // SAFETY: Base64 encoding only produces ASCII bytes. Even if our assumptions are incorrect, - // and Base64 bytes do not fill `hashed_key` completely, the remaining bytes are 0, so also ASCII - let hashed_key = unsafe { ArenaString::from_utf8_unchecked(hashed_key) }; + // and Base64 bytes do not fill `hashed_key` completely, the remaining bytes are 0, so also ASCII. + let hashed_key_bytes = unsafe { hashed_key.as_mut_str().as_bytes_mut() }; + let encoded_bytes = BASE64_STANDARD.encode_slice(hash, hashed_key_bytes).unwrap(); + debug_assert_eq!(encoded_bytes, ENCODED_LEN); Atom::from(hashed_key) }; diff --git a/crates/oxc_traverse/src/context/uid.rs b/crates/oxc_traverse/src/context/uid.rs index 81d682bc8d83c..b4ee17b137253 100644 --- a/crates/oxc_traverse/src/context/uid.rs +++ b/crates/oxc_traverse/src/context/uid.rs @@ -1,9 +1,9 @@ -use std::{iter, str}; +use std::str; use itoa::Buffer as ItoaBuffer; use rustc_hash::FxHashMap; -use oxc_allocator::{Allocator, String as ArenaString}; +use oxc_allocator::{Allocator, StringBuilder as ArenaStringBuilder}; use oxc_semantic::Scoping; use oxc_span::Atom; @@ -288,11 +288,11 @@ impl<'a> UidGenerator<'a> { if uid_name.underscore_count == 1 { Atom::from_strs_array_in(["_", base, digits], self.allocator) } else { - let mut uid = ArenaString::with_capacity_in( + let mut uid = ArenaStringBuilder::with_capacity_in( uid_name.underscore_count as usize + base.len() + digits.len(), self.allocator, ); - uid.extend(iter::repeat_n("_", uid_name.underscore_count as usize)); + uid.push_ascii_byte_repeat(b'_', uid_name.underscore_count as usize); uid.push_str(base); uid.push_str(digits); Atom::from(uid)