Skip to content

Commit

Permalink
feat: support RawStringSource and RawBufferSource
Browse files Browse the repository at this point in the history
  • Loading branch information
h-a-n-a committed Dec 4, 2024
1 parent 58994d9 commit f3165d6
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub use cached_source::CachedSource;
pub use concat_source::ConcatSource;
pub use error::{Error, Result};
pub use original_source::OriginalSource;
pub use raw_source::RawSource;
pub use raw_source::{RawBufferSource, RawSource, RawStringSource};
pub use replace_source::{ReplaceSource, ReplacementEnforce};
pub use source::{
BoxSource, MapOptions, Mapping, OriginalLocation, Source, SourceExt,
Expand Down
209 changes: 209 additions & 0 deletions src/raw_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,215 @@ impl<'a> StreamChunks<'a> for RawSource {
}
}

/// A string variant of [RawSource].
///
/// - [webpack-sources docs](https://github.com/webpack/webpack-sources/#rawsource).
///
/// ```
/// use rspack_sources::{MapOptions, RawStringSource, Source};
///
/// let code = "some source code";
/// let s = RawStringSource::from(code.to_string());
/// assert_eq!(s.source(), code);
/// assert_eq!(s.map(&MapOptions::default()), None);
/// assert_eq!(s.size(), 16);
/// ```
#[derive(Clone, PartialEq, Eq)]
pub struct RawStringSource(Cow<'static, str>);

#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
static_assertions::assert_eq_size!(RawStringSource, [u8; 24]);

impl RawStringSource {
/// Create a new [RawStringSource] from a static &str.
///
/// ```
/// use rspack_sources::{RawStringSource, Source};
///
/// let code = "some source code";
/// let s = RawStringSource::from_static(code);
/// assert_eq!(s.source(), code);
/// ```
pub fn from_static(s: &'static str) -> Self {
Self(Cow::Borrowed(s))
}
}

impl From<String> for RawStringSource {
fn from(value: String) -> Self {
Self(Cow::Owned(value))
}
}

impl From<&str> for RawStringSource {
fn from(value: &str) -> Self {
Self(Cow::Owned(value.to_owned()))
}
}

impl Source for RawStringSource {
fn source(&self) -> Cow<str> {
Cow::Borrowed(&self.0)
}

fn buffer(&self) -> Cow<[u8]> {
Cow::Borrowed(self.0.as_bytes())
}

fn size(&self) -> usize {
self.0.len()
}

fn map(&self, _: &MapOptions) -> Option<SourceMap> {
None
}

fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
writer.write_all(self.0.as_bytes())
}
}

impl std::fmt::Debug for RawStringSource {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> Result<(), std::fmt::Error> {
let mut d = f.debug_tuple("RawStringSource");
d.field(&self.0.chars().take(50).collect::<String>());
d.finish()
}
}

impl Hash for RawStringSource {
fn hash<H: Hasher>(&self, state: &mut H) {
"RawStringSource".hash(state);
self.buffer().hash(state);
}
}

impl<'a> StreamChunks<'a> for RawStringSource {
fn stream_chunks(
&'a self,
options: &MapOptions,
on_chunk: OnChunk<'_, 'a>,
on_source: OnSource<'_, 'a>,
on_name: OnName<'_, 'a>,
) -> crate::helpers::GeneratedInfo {
if options.final_source {
get_generated_source_info(&self.source())
} else {
stream_chunks_of_raw_source(
&self.0, options, on_chunk, on_source, on_name,
)
}
}
}

/// A buffer variant of [RawSource].
///
/// - [webpack-sources docs](https://github.com/webpack/webpack-sources/#rawsource).
///
/// ```
/// use rspack_sources::{MapOptions, RawBufferSource, Source};
///
/// let code = "some source code".as_bytes();
/// let s = RawBufferSource::from(code);
/// assert_eq!(s.buffer(), code);
/// assert_eq!(s.map(&MapOptions::default()), None);
/// assert_eq!(s.size(), 16);
/// ```
#[derive(Clone, PartialEq, Eq)]
pub struct RawBufferSource {
value: Vec<u8>,
value_as_string: OnceLock<String>,
}

impl From<Vec<u8>> for RawBufferSource {
fn from(value: Vec<u8>) -> Self {
Self {
value,
value_as_string: Default::default(),
}
}
}

impl From<&[u8]> for RawBufferSource {
fn from(value: &[u8]) -> Self {
Self {
value: value.to_vec(),
value_as_string: Default::default(),
}
}
}

impl Source for RawBufferSource {
fn source(&self) -> Cow<str> {
Cow::Borrowed(
self
.value_as_string
.get_or_init(|| String::from_utf8_lossy(&self.value).to_string()),
)
}

fn buffer(&self) -> Cow<[u8]> {
Cow::Borrowed(&self.value)
}

fn size(&self) -> usize {
self.value.len()
}

fn map(&self, _: &MapOptions) -> Option<SourceMap> {
None
}

fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
writer.write_all(&self.value)
}
}

impl std::fmt::Debug for RawBufferSource {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> Result<(), std::fmt::Error> {
let mut d = f.debug_tuple("RawBufferSource");
d.field(&self.value.iter().take(50).copied().collect::<Vec<u8>>());
d.finish()
}
}

impl Hash for RawBufferSource {
fn hash<H: Hasher>(&self, state: &mut H) {
"RawBufferSource".hash(state);
self.buffer().hash(state);
}
}

impl<'a> StreamChunks<'a> for RawBufferSource {
fn stream_chunks(
&'a self,
options: &MapOptions,
on_chunk: OnChunk<'_, 'a>,
on_source: OnSource<'_, 'a>,
on_name: OnName<'_, 'a>,
) -> crate::helpers::GeneratedInfo {
if options.final_source {
get_generated_source_info(&self.source())
} else {
stream_chunks_of_raw_source(
self
.value_as_string
.get_or_init(|| String::from_utf8_lossy(&self.value).to_string()),
options,
on_chunk,
on_source,
on_name,
)
}
}
}

#[cfg(test)]
mod tests {
use crate::{ConcatSource, OriginalSource, ReplaceSource, SourceExt};
Expand Down
1 change: 0 additions & 1 deletion src/replace_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,6 @@ mod tests {
let mut last_line = 0;
sourcemap
.decoded_mappings()
.into_iter()
.map(|token| {
format!(
"{}:{} ->{} {}:{}{}",
Expand Down
24 changes: 19 additions & 5 deletions src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,8 +486,8 @@ mod tests {
use std::collections::HashMap;

use crate::{
CachedSource, ConcatSource, OriginalSource, RawSource, ReplaceSource,
SourceMapSource, WithoutOriginalOptions,
CachedSource, ConcatSource, OriginalSource, RawBufferSource, RawSource,
RawStringSource, ReplaceSource, SourceMapSource, WithoutOriginalOptions,
};

use super::*;
Expand Down Expand Up @@ -520,14 +520,24 @@ mod tests {
CachedSource::new(RawSource::from("e")).hash(&mut state);
ReplaceSource::new(RawSource::from("f")).hash(&mut state);
RawSource::from("g").boxed().hash(&mut state);
RawStringSource::from_static("a").hash(&mut state);
RawBufferSource::from("a".as_bytes()).hash(&mut state);
(&RawSource::from("h") as &dyn Source).hash(&mut state);
ReplaceSource::new(RawSource::from("i").boxed()).hash(&mut state);
assert_eq!(format!("{:x}", state.finish()), "ef733b8b8ee61bf0");
assert_eq!(format!("{:x}", state.finish()), "709931db47fa47dc");
}

#[test]
fn eq_available() {
assert_eq!(RawSource::from("a"), RawSource::from("a"));
assert_eq!(
RawStringSource::from_static("a"),
RawStringSource::from_static("a")
);
assert_eq!(
RawBufferSource::from("a".as_bytes()),
RawBufferSource::from("a".as_bytes())
);
assert_eq!(OriginalSource::new("b", ""), OriginalSource::new("b", ""));
assert_eq!(
SourceMapSource::new(WithoutOriginalOptions {
Expand Down Expand Up @@ -569,7 +579,7 @@ mod tests {
}

#[test]
#[allow(clippy::clone_double_ref)]
#[allow(suspicious_double_ref_op)]
fn clone_available() {
let a = RawSource::from("a");
assert_eq!(a, a.clone());
Expand All @@ -595,6 +605,10 @@ mod tests {
assert_eq!(i, i.clone());
let j = CachedSource::new(RawSource::from("j").boxed());
assert_eq!(j, j.clone());
let k = RawStringSource::from_static("k");
assert_eq!(k, k.clone());
let l = RawBufferSource::from("l".as_bytes());
assert_eq!(l, l.clone());
}

#[test]
Expand All @@ -606,7 +620,7 @@ mod tests {
}

#[test]
#[allow(clippy::clone_double_ref)]
#[allow(suspicious_double_ref_op)]
fn ref_dyn_source_use_hashmap_available() {
let mut map = HashMap::new();
let a = &RawSource::from("a") as &dyn Source;
Expand Down

0 comments on commit f3165d6

Please sign in to comment.