Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 16 additions & 37 deletions crates/oxc_codegen/src/code_buffer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::mem;

use assert_unchecked::assert_unchecked;

/// A string builder for constructing source code.
Expand All @@ -8,8 +6,7 @@ use assert_unchecked::assert_unchecked;
/// Essentially same as `String` but with additional methods.
///
/// Use one of the various `print_*` methods to add text into the buffer.
/// When you are done, call [`take_source_text`] or `String::from(code_buffer)`
/// to extract the final [`String`].
/// When you are done, call [`into_string`] to extract the final [`String`].
///
/// # Example
/// ```
Expand All @@ -26,10 +23,10 @@ use assert_unchecked::assert_unchecked;
/// code.print_str(" console.log('Hello, world!');\n");
/// code.print_str("}\n");
///
/// let source = code.take_source_text();
/// let source = code.into_string();
/// ```
///
/// [`take_source_text`]: CodeBuffer::take_source_text
/// [`into_string`]: CodeBuffer::into_string
#[derive(Debug, Default, Clone)]
pub struct CodeBuffer {
/// INVARIANT: `buf` is a valid UTF-8 string.
Expand All @@ -46,7 +43,7 @@ impl CodeBuffer {
///
/// // use `code` to build new source text
/// code.print_str("fn main() { println!(\"Hello, world!\"); }");
/// let source_text = code.take_source_text();
/// let source_text = code.into_string();
/// ```
#[inline]
pub fn new() -> Self {
Expand Down Expand Up @@ -187,7 +184,7 @@ impl CodeBuffer {
/// code.print_ascii_byte(b'o');
/// code.print_ascii_byte(b'o');
///
/// let source = code.take_source_text();
/// let source = code.into_string();
/// assert_eq!(source, "foo");
/// ```
#[inline]
Expand All @@ -212,7 +209,7 @@ impl CodeBuffer {
///
/// It is safe for a single call to temporarily result in invalid UTF-8, as long as
/// UTF-8 integrity is restored before calls to any other `print_*` method or
/// [`take_source_text`]. This lets you, for example, print an 4-byte Unicode character
/// [`into_string`]. This lets you, for example, print an 4-byte Unicode character
/// using 4 separate calls to this method. However, consider using [`print_bytes_unchecked`]
/// instead for that use case.
///
Expand All @@ -237,7 +234,7 @@ impl CodeBuffer {
///
/// [`print_ascii_byte`]: CodeBuffer::print_ascii_byte
/// [`print_char`]: CodeBuffer::print_char
/// [`take_source_text`]: CodeBuffer::take_source_text
/// [`into_string`]: CodeBuffer::into_string
/// [`print_bytes_unchecked`]: CodeBuffer::print_bytes_unchecked
#[inline]
pub unsafe fn print_byte_unchecked(&mut self, byte: u8) {
Expand Down Expand Up @@ -382,31 +379,25 @@ impl CodeBuffer {
&self.buf
}

/// Convert a buffer into a string of source code, leaving its internal buffer empty.
///
/// It is safe to re-use a `CodeBuffer` after calling this method, but there is little benefit
/// to doing so, as the `CodeBuffer` will be left in an empty state with no backing allocation.
///
/// You may alternatively use `String::from(code_buffer)`, which may be slightly more efficient.
/// Consume buffer and return source code as a `String`.
///
/// # Example
/// ```
/// use oxc_codegen::CodeBuffer;
/// let mut code = CodeBuffer::new();
/// code.print_str("console.log('foo');");
///
/// let source = code.take_source_text();
/// let source = code.into_string();
/// assert_eq!(source, "console.log('foo');");
/// assert!(code.is_empty());
/// ```
#[must_use]
#[inline]
pub fn take_source_text(&mut self) -> String {
pub fn into_string(self) -> String {
if cfg!(debug_assertions) {
String::from_utf8(mem::take(&mut self.buf)).unwrap()
String::from_utf8(self.buf).unwrap()
} else {
// SAFETY: All methods of `CodeBuffer` ensure `buf` is valid UTF-8
unsafe { String::from_utf8_unchecked(mem::take(&mut self.buf)) }
unsafe { String::from_utf8_unchecked(self.buf) }
}
}
}
Expand All @@ -420,13 +411,8 @@ impl AsRef<[u8]> for CodeBuffer {

impl From<CodeBuffer> for String {
#[inline]
fn from(buffer: CodeBuffer) -> Self {
if cfg!(debug_assertions) {
String::from_utf8(buffer.buf).unwrap()
} else {
// SAFETY: All methods of `CodeBuffer` ensure `buf` is valid UTF-8
unsafe { String::from_utf8_unchecked(buffer.buf) }
}
fn from(code: CodeBuffer) -> Self {
code.into_string()
}
}

Expand All @@ -452,20 +438,13 @@ mod test {
}

#[test]
fn into_source_string() {
fn into_string() {
let s = "Hello, world!";
let mut code = CodeBuffer::with_capacity(s.len());
code.print_str(s);

let source = code.take_source_text();
let source = code.into_string();
assert_eq!(source, s);

// buffer has been emptied
assert!(code.is_empty());
assert_eq!(code.len(), 0);
let empty_slice: &[u8] = &[];
assert_eq!(code.as_bytes(), empty_slice);
assert_eq!(String::from(code), "");
}

#[test]
Expand Down
10 changes: 5 additions & 5 deletions crates/oxc_codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,13 @@ impl<'a> Default for Codegen<'a> {
}

impl<'a> From<Codegen<'a>> for String {
fn from(mut val: Codegen<'a>) -> Self {
fn from(val: Codegen<'a>) -> Self {
val.into_source_text()
}
}

impl<'a> From<Codegen<'a>> for Cow<'a, str> {
fn from(mut val: Codegen<'a>) -> Self {
fn from(val: Codegen<'a>) -> Self {
Cow::Owned(val.into_source_text())
}
}
Expand Down Expand Up @@ -215,14 +215,14 @@ impl<'a> Codegen<'a> {
}

program.print(&mut self, Context::default());
let code = self.into_source_text();
let code = self.code.into_string();
let map = self.sourcemap_builder.map(SourcemapBuilder::into_sourcemap);
CodegenReturn { code, map }
}

#[must_use]
pub fn into_source_text(&mut self) -> String {
self.code.take_source_text()
pub fn into_source_text(self) -> String {
self.code.into_string()
}

/// Push a single ASCII byte into the buffer.
Expand Down