From 926bc5e83cfea095da6abc3303b0261e1263a39d Mon Sep 17 00:00:00 2001
From: Cong-Cong <dacongsama@live.com>
Date: Thu, 5 Dec 2024 18:32:21 +0800
Subject: [PATCH 1/2] perf: cow map

---
 src/cached_source.rs     | 36 ++++++++++++++++++++++++++-----
 src/concat_source.rs     | 22 +++++++++----------
 src/original_source.rs   |  4 ++--
 src/raw_source.rs        |  6 +++---
 src/replace_source.rs    |  4 ++--
 src/source.rs            |  8 +++----
 src/source_map_source.rs | 46 +++++++++++++++++++++++-----------------
 tests/compat_source.rs   |  6 +++---
 8 files changed, 82 insertions(+), 50 deletions(-)

diff --git a/src/cached_source.rs b/src/cached_source.rs
index 7b8ef2dc..3e307184 100644
--- a/src/cached_source.rs
+++ b/src/cached_source.rs
@@ -94,13 +94,39 @@ impl<T: Source + Hash + PartialEq + Eq + 'static> Source for CachedSource<T> {
     self.source().len()
   }
 
-  fn map(&self, options: &MapOptions) -> Option<SourceMap> {
+  fn map(&self, options: &MapOptions) -> Option<Cow<SourceMap>> {
     if let Some(map) = self.cached_maps.get(options) {
-      map.clone()
+      match map.as_ref() {
+        Some(map) => {
+          #[allow(unsafe_code)]
+          // SAFETY: We guarantee that once a `SourceMap` is stored in the cache, it will never be removed.
+          // Therefore, even if we force its lifetime to be longer, the reference remains valid.
+          // This is based on the following assumptions:
+          // 1. `SourceMap` will be valid for the entire duration of the application.
+          // 2. The cached `SourceMap` will not be manually removed or replaced, ensuring the reference's safety.
+          let map = unsafe { std::mem::transmute::<&SourceMap, &'static SourceMap>(map) };
+          Some(Cow::Borrowed(map))
+        },
+        None => None,
+      }
     } else {
       let map = self.inner.map(options);
-      self.cached_maps.insert(options.clone(), map.clone());
-      map
+      self
+        .cached_maps
+        .insert(options.clone(), map.map(|m| m.into_owned()));
+      match self.cached_maps.get(options).unwrap().as_ref() {
+        Some(map) => {
+          #[allow(unsafe_code)]
+          // SAFETY: We guarantee that once a `SourceMap` is stored in the cache, it will never be removed.
+          // Therefore, even if we force its lifetime to be longer, the reference remains valid.
+          // This is based on the following assumptions:
+          // 1. `SourceMap` will be valid for the entire duration of the application.
+          // 2. The cached `SourceMap` will not be manually removed or replaced, ensuring the reference's safety.
+          let map = unsafe { std::mem::transmute::<&SourceMap, &'static SourceMap>(map) };
+          Some(Cow::Borrowed(map))
+        },
+        None => None,
+      }
     }
   }
 
@@ -254,7 +280,7 @@ mod tests {
     );
     assert_eq!(
       *clone.cached_maps.get(&map_options).unwrap().value(),
-      source.map(&map_options)
+      source.map(&map_options).map(|map| map.into_owned())
     );
   }
 
diff --git a/src/concat_source.rs b/src/concat_source.rs
index 7435fcb6..230785ca 100644
--- a/src/concat_source.rs
+++ b/src/concat_source.rs
@@ -39,7 +39,7 @@ use crate::{
 ///   "Hello World\nconsole.log('test');\nconsole.log('test2');\nHello2\n"
 /// );
 /// assert_eq!(
-///   source.map(&MapOptions::new(false)).unwrap(),
+///   source.map(&MapOptions::new(false)).unwrap().into_owned(),
 ///   SourceMap::from_json(
 ///     r#"{
 ///       "version": 3,
@@ -127,8 +127,8 @@ impl Source for ConcatSource {
     self.children().iter().map(|child| child.size()).sum()
   }
 
-  fn map(&self, options: &MapOptions) -> Option<SourceMap> {
-    get_map(self, options)
+  fn map(&self, options: &MapOptions) -> Option<Cow<SourceMap>> {
+    get_map(self, options).map(Cow::Owned)
   }
 
   fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
@@ -347,7 +347,7 @@ mod tests {
     assert_eq!(source.size(), 62);
     assert_eq!(source.source(), expected_source);
     assert_eq!(
-      source.map(&MapOptions::new(false)).unwrap(),
+      source.map(&MapOptions::new(false)).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "version": 3,
@@ -363,7 +363,7 @@ mod tests {
       .unwrap()
     );
     assert_eq!(
-      source.map(&MapOptions::default()).unwrap(),
+      source.map(&MapOptions::default()).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "version": 3,
@@ -397,7 +397,7 @@ mod tests {
     assert_eq!(source.size(), 62);
     assert_eq!(source.source(), expected_source);
     assert_eq!(
-      source.map(&MapOptions::new(false)).unwrap(),
+      source.map(&MapOptions::new(false)).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "version": 3,
@@ -413,7 +413,7 @@ mod tests {
       .unwrap()
     );
     assert_eq!(
-      source.map(&MapOptions::default()).unwrap(),
+      source.map(&MapOptions::default()).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "version": 3,
@@ -447,7 +447,7 @@ mod tests {
     assert_eq!(source.size(), 62);
     assert_eq!(source.source(), expected_source);
     assert_eq!(
-      source.map(&MapOptions::new(false)).unwrap(),
+      source.map(&MapOptions::new(false)).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "version": 3,
@@ -463,7 +463,7 @@ mod tests {
       .unwrap()
     );
     assert_eq!(
-      source.map(&MapOptions::default()).unwrap(),
+      source.map(&MapOptions::default()).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "version": 3,
@@ -513,7 +513,7 @@ mod tests {
     assert_eq!(source.buffer(), expected_source.as_bytes());
 
     let map = source.map(&MapOptions::new(false)).unwrap();
-    assert_eq!(map, expected_map1);
+    assert_eq!(map.into_owned(), expected_map1);
 
     // TODO: test hash
   }
@@ -549,7 +549,7 @@ mod tests {
     ]);
 
     assert_eq!(
-      source.map(&MapOptions::default()).unwrap(),
+      source.map(&MapOptions::default()).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "mappings": "AAAA,K,CCAA,M;ADAA;;ACAA",
diff --git a/src/original_source.rs b/src/original_source.rs
index b73c275d..b0f57d92 100644
--- a/src/original_source.rs
+++ b/src/original_source.rs
@@ -63,8 +63,8 @@ impl Source for OriginalSource {
     self.value.len()
   }
 
-  fn map(&self, options: &MapOptions) -> Option<SourceMap> {
-    get_map(self, options)
+  fn map(&self, options: &MapOptions) -> Option<Cow<SourceMap>> {
+    get_map(self, options).map(Cow::Owned)
   }
 
   fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
diff --git a/src/raw_source.rs b/src/raw_source.rs
index 388ea69d..4db5205a 100644
--- a/src/raw_source.rs
+++ b/src/raw_source.rs
@@ -137,7 +137,7 @@ impl Source for RawSource {
     }
   }
 
-  fn map(&self, _: &MapOptions) -> Option<SourceMap> {
+  fn map(&self, _: &MapOptions) -> Option<Cow<SourceMap>> {
     None
   }
 
@@ -274,7 +274,7 @@ impl Source for RawStringSource {
     self.0.len()
   }
 
-  fn map(&self, _: &MapOptions) -> Option<SourceMap> {
+  fn map(&self, _: &MapOptions) -> Option<Cow<SourceMap>> {
     None
   }
 
@@ -373,7 +373,7 @@ impl Source for RawBufferSource {
     self.value.len()
   }
 
-  fn map(&self, _: &MapOptions) -> Option<SourceMap> {
+  fn map(&self, _: &MapOptions) -> Option<Cow<SourceMap>> {
     None
   }
 
diff --git a/src/replace_source.rs b/src/replace_source.rs
index 378cd841..7673ca17 100644
--- a/src/replace_source.rs
+++ b/src/replace_source.rs
@@ -216,13 +216,13 @@ impl<T: Source + Hash + PartialEq + Eq + 'static> Source for ReplaceSource<T> {
     self.source().len()
   }
 
-  fn map(&self, options: &crate::MapOptions) -> Option<SourceMap> {
+  fn map(&self, options: &crate::MapOptions) -> Option<Cow<SourceMap>> {
     let replacements = self.replacements.lock().unwrap();
     if replacements.is_empty() {
       return self.inner.map(options);
     }
     drop(replacements);
-    get_map(self, options)
+    get_map(self, options).map(Cow::Owned)
   }
 
   fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
diff --git a/src/source.rs b/src/source.rs
index 25adbb5c..a43e555b 100644
--- a/src/source.rs
+++ b/src/source.rs
@@ -39,7 +39,7 @@ pub trait Source:
   fn size(&self) -> usize;
 
   /// Get the [SourceMap].
-  fn map(&self, options: &MapOptions) -> Option<SourceMap>;
+  fn map(&self, options: &MapOptions) -> Option<Cow<SourceMap>>;
 
   /// Update hash based on the source.
   fn update_hash(&self, state: &mut dyn Hasher) {
@@ -63,7 +63,7 @@ impl Source for BoxSource {
     self.as_ref().size()
   }
 
-  fn map(&self, options: &MapOptions) -> Option<SourceMap> {
+  fn map(&self, options: &MapOptions) -> Option<Cow<SourceMap>> {
     self.as_ref().map(options)
   }
 
@@ -370,8 +370,8 @@ impl SourceMap {
   }
 
   /// Generate source map to a json string.
-  pub fn to_json(self) -> Result<String> {
-    let json = simd_json::serde::to_string(&self)?;
+  pub fn to_json(&self) -> Result<String> {
+    let json = simd_json::serde::to_string(self)?;
     Ok(json)
   }
 
diff --git a/src/source_map_source.rs b/src/source_map_source.rs
index 07b32a05..0613e4ec 100644
--- a/src/source_map_source.rs
+++ b/src/source_map_source.rs
@@ -100,11 +100,11 @@ impl Source for SourceMapSource {
     self.value.len()
   }
 
-  fn map(&self, options: &MapOptions) -> Option<SourceMap> {
+  fn map(&self, options: &MapOptions) -> Option<Cow<SourceMap>> {
     if self.inner_source_map.is_none() {
-      return Some(self.source_map.clone());
+      return Some(Cow::Borrowed(&self.source_map));
     }
-    get_map(self, options)
+    get_map(self, options).map(Cow::Owned)
   }
 
   fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
@@ -215,7 +215,9 @@ mod tests {
       name: "text",
       source_map: source_r_map.clone(),
       original_source: Some(inner_source.source().to_string()),
-      inner_source_map: inner_source.map(&MapOptions::default()),
+      inner_source_map: inner_source
+        .map(&MapOptions::default())
+        .map(|map| map.into_owned()),
       remove_original_source: false,
     });
     let sms2 = SourceMapSource::new(SourceMapSourceOptions {
@@ -223,7 +225,9 @@ mod tests {
       name: "text",
       source_map: source_r_map,
       original_source: Some(inner_source.source().to_string()),
-      inner_source_map: inner_source.map(&MapOptions::default()),
+      inner_source_map: inner_source
+        .map(&MapOptions::default())
+        .map(|map| map.into_owned()),
       remove_original_source: true,
     });
     let expected_content =
@@ -231,7 +235,7 @@ mod tests {
     assert_eq!(sms1.source(), expected_content);
     assert_eq!(sms2.source(), expected_content);
     assert_eq!(
-      sms1.map(&MapOptions::default()).unwrap(),
+      sms1.map(&MapOptions::default()).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "mappings": "YAAAA,K,CAAMC;AACN,O,MAAU;ACCC,O,CAAM",
@@ -247,7 +251,7 @@ mod tests {
       .unwrap(),
     );
     assert_eq!(
-      sms2.map(&MapOptions::default()).unwrap(),
+      sms2.map(&MapOptions::default()).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "mappings": "YAAAA,K,CAAMC;AACN,O,MAAU",
@@ -300,7 +304,7 @@ mod tests {
     let source = ConcatSource::new(sources);
     assert_eq!(source.source(), "hi world\nhi world\nhi world\n");
     assert_eq!(
-      source.map(&MapOptions::default()).unwrap(),
+      source.map(&MapOptions::default()).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "mappings": "AAAA;;ACAA,CAAC,CAAI",
@@ -313,7 +317,7 @@ mod tests {
       .unwrap()
     );
     assert_eq!(
-      source.map(&MapOptions::new(false)).unwrap(),
+      source.map(&MapOptions::new(false)).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "mappings": "AAAA;;ACAA",
@@ -423,11 +427,11 @@ mod tests {
     }
 
     test_cached!(source, |s: &dyn Source| s.source().to_string());
-    test_cached!(source, |s: &dyn Source| s.map(&MapOptions::default()));
+    test_cached!(source, |s: &dyn Source| s.map(&MapOptions::default()).map(|m| m.into_owned()));
     test_cached!(source, |s: &dyn Source| s.map(&MapOptions {
       columns: false,
       final_source: true
-    }));
+    }).map(|m| m.into_owned()));
   }
 
   #[test]
@@ -458,7 +462,7 @@ mod tests {
       remove_original_source: false,
     });
     assert_eq!(
-      source.map(&MapOptions::default()).unwrap(),
+      source.map(&MapOptions::default()).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "mappings": "AAAA",
@@ -502,7 +506,7 @@ mod tests {
     assert_eq!(source.source(), "Message: H W!");
     assert_eq!(source.size(), 13);
     assert_eq!(
-      source.map(&MapOptions::default()).unwrap(),
+      source.map(&MapOptions::default()).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "mappings": "AAAAA,SCAA,ECAMC,C",
@@ -555,7 +559,7 @@ mod tests {
     });
     let map = source.map(&MapOptions::default()).unwrap();
     assert_eq!(
-      map,
+      map.into_owned(),
       SourceMap::from_json(
         r#"{
           "version": 3,
@@ -574,7 +578,7 @@ mod tests {
     let source = SourceMapSource::new(WithoutOriginalOptions {
       value: "console.log('a')\n",
       name: "a.js",
-      source_map: original.map(&MapOptions::new(false)).unwrap(),
+      source_map: original.map(&MapOptions::new(false)).unwrap().into_owned(),
     });
     let source = ConcatSource::new([
       RawSource::from("\n").boxed(),
@@ -607,8 +611,10 @@ mod tests {
       }"#,
     )
     .unwrap();
-    let inner_source_map =
-      inner_source.map(&MapOptions::default()).map(|mut map| {
+    let inner_source_map = inner_source
+      .map(&MapOptions::default())
+      .map(|map| {
+        let mut map = map.into_owned();
         map.set_source_root(Some("/path/to/folder/".to_string()));
         map
       });
@@ -621,7 +627,7 @@ mod tests {
       remove_original_source: false,
     });
     assert_eq!(
-      sms.map(&MapOptions::default()).unwrap(),
+      sms.map(&MapOptions::default()).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "mappings": "YAAAA,K,CAAMC;AACN,O,MAAU;ACCC,O,CAAM",
@@ -668,7 +674,7 @@ mod tests {
       remove_original_source: false,
     });
     assert_eq!(
-      source.map(&MapOptions::new(false)).unwrap(),
+      source.map(&MapOptions::new(false)).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "mappings": "AAAA",
@@ -710,7 +716,7 @@ mod tests {
       remove_original_source: false,
     });
     assert_eq!(
-      source.map(&MapOptions::default()).unwrap(),
+      source.map(&MapOptions::default()).unwrap().into_owned(),
       SourceMap::from_json(
         r#"{
           "version": 3,
diff --git a/tests/compat_source.rs b/tests/compat_source.rs
index 9079d26c..dc8a1ad4 100644
--- a/tests/compat_source.rs
+++ b/tests/compat_source.rs
@@ -24,8 +24,8 @@ impl Source for CompatSource {
     42
   }
 
-  fn map(&self, _options: &MapOptions) -> Option<SourceMap> {
-    self.1.clone()
+  fn map(&self, _options: &MapOptions) -> Option<Cow<SourceMap>> {
+    self.1.as_ref().map(Cow::Borrowed)
   }
 
   fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
@@ -116,5 +116,5 @@ fn should_generate_correct_source_map() {
   .unwrap();
 
   assert_eq!(source, expected_source);
-  assert_eq!(map, expected_source_map)
+  assert_eq!(map.into_owned(), expected_source_map)
 }

From a144ae6afb4aa3d2f1cd48c703cfd099e7059423 Mon Sep 17 00:00:00 2001
From: Cong-Cong <dacongsama@live.com>
Date: Thu, 5 Dec 2024 18:34:01 +0800
Subject: [PATCH 2/2] fix: fmt

---
 src/cached_source.rs     | 12 ++++++++----
 src/source_map_source.rs | 19 +++++++++++--------
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/src/cached_source.rs b/src/cached_source.rs
index 3e307184..876f4473 100644
--- a/src/cached_source.rs
+++ b/src/cached_source.rs
@@ -104,9 +104,11 @@ impl<T: Source + Hash + PartialEq + Eq + 'static> Source for CachedSource<T> {
           // This is based on the following assumptions:
           // 1. `SourceMap` will be valid for the entire duration of the application.
           // 2. The cached `SourceMap` will not be manually removed or replaced, ensuring the reference's safety.
-          let map = unsafe { std::mem::transmute::<&SourceMap, &'static SourceMap>(map) };
+          let map = unsafe {
+            std::mem::transmute::<&SourceMap, &'static SourceMap>(map)
+          };
           Some(Cow::Borrowed(map))
-        },
+        }
         None => None,
       }
     } else {
@@ -122,9 +124,11 @@ impl<T: Source + Hash + PartialEq + Eq + 'static> Source for CachedSource<T> {
           // This is based on the following assumptions:
           // 1. `SourceMap` will be valid for the entire duration of the application.
           // 2. The cached `SourceMap` will not be manually removed or replaced, ensuring the reference's safety.
-          let map = unsafe { std::mem::transmute::<&SourceMap, &'static SourceMap>(map) };
+          let map = unsafe {
+            std::mem::transmute::<&SourceMap, &'static SourceMap>(map)
+          };
           Some(Cow::Borrowed(map))
-        },
+        }
         None => None,
       }
     }
diff --git a/src/source_map_source.rs b/src/source_map_source.rs
index 0613e4ec..5f2da52b 100644
--- a/src/source_map_source.rs
+++ b/src/source_map_source.rs
@@ -427,11 +427,15 @@ mod tests {
     }
 
     test_cached!(source, |s: &dyn Source| s.source().to_string());
-    test_cached!(source, |s: &dyn Source| s.map(&MapOptions::default()).map(|m| m.into_owned()));
-    test_cached!(source, |s: &dyn Source| s.map(&MapOptions {
-      columns: false,
-      final_source: true
-    }).map(|m| m.into_owned()));
+    test_cached!(source, |s: &dyn Source| s
+      .map(&MapOptions::default())
+      .map(|m| m.into_owned()));
+    test_cached!(source, |s: &dyn Source| s
+      .map(&MapOptions {
+        columns: false,
+        final_source: true
+      })
+      .map(|m| m.into_owned()));
   }
 
   #[test]
@@ -611,9 +615,8 @@ mod tests {
       }"#,
     )
     .unwrap();
-    let inner_source_map = inner_source
-      .map(&MapOptions::default())
-      .map(|map| {
+    let inner_source_map =
+      inner_source.map(&MapOptions::default()).map(|map| {
         let mut map = map.into_owned();
         map.set_source_root(Some("/path/to/folder/".to_string()));
         map