Description: avoid not-in-Debian crate bytes-str
 This essentially reverts upstream git commit 6f00973.
Author: Jonas Smedegaard <dr@jones.dk>
Forwarded: not-needed
Last-Update: 2025-08-08
---
This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,7 +29,6 @@
   bitflags                  = "2.5.0"
   browserslist-rs           = "0.19.0"
   bumpalo                   = "3.16.0"
-  bytes-str                 = "0.2.5"
   blake3                    = "1.5.4"
   cargo_metadata            = ">= 0.18.1, <= 0.19"
   changesets                = "0.2.2"
--- a/crates/binding_macros/src/wasm.rs
+++ b/crates/binding_macros/src/wasm.rs
@@ -115,7 +115,7 @@
                       .map_err(|e| $crate::wasm::anyhow::anyhow!("failed to parse options: {}", e))?
                   };
 
-                  let fm = c.cm.new_source_file($crate::wasm::FileName::Anon.into(), String::from(s));
+                  let fm = c.cm.new_source_file($crate::wasm::FileName::Anon.into(), s.into());
                   let program = $crate::wasm::anyhow::Context::context(c.minify(fm, handler, &opts, Default::default()), "failed to minify file")?;
 
                   program
@@ -171,7 +171,7 @@
                         .map_err(|e| $crate::wasm::anyhow::anyhow!("failed to parse options: {}", e))?
                   };
 
-                  let fm = c.cm.new_source_file($crate::wasm::FileName::Anon.into(), String::from(s));
+                  let fm = c.cm.new_source_file($crate::wasm::FileName::Anon.into(), s.into());
 
                   let cmts = c.comments().clone();
                   let comments = if opts.comments {
@@ -379,7 +379,7 @@
                               } else {
                                 $crate::wasm::FileName::Real(opts.filename.clone().into()).into()
                               },
-                              String::from(s),
+                              s.into(),
                           );
                           let cm = c.cm.clone();
                           let file = fm.clone();
--- a/crates/swc_common/Cargo.toml
+++ b/crates/swc_common/Cargo.toml
@@ -33,15 +33,8 @@
 
 tty-emitter = ["termcolor"]
 
-__rkyv = []
-rkyv-impl = [
-  "__rkyv",
-  "rkyv",
-  "swc_atoms/rkyv-impl",
-  "bytes-str/rkyv",
-  "bytecheck",
-  "rancor",
-]
+__rkyv    = []
+rkyv-impl = ["__rkyv", "rkyv", "swc_atoms/rkyv-impl", "bytecheck", "rancor"]
 
 shrink-to-fit = ["dep:shrink-to-fit", "swc_atoms/shrink-to-fit"]
 
@@ -50,7 +43,6 @@
 anyhow                = { workspace = true }
 arbitrary             = { workspace = true, features = ["derive"], optional = true }
 bytecheck             = { workspace = true, optional = true }
-bytes-str             = { workspace = true, features = ["serde"] }
 either                = { workspace = true }
 new_debug_unreachable = { workspace = true }
 num-bigint            = { workspace = true }
--- a/crates/swc_common/src/input.rs
+++ b/crates/swc_common/src/input.rs
@@ -303,15 +303,17 @@
 
 #[cfg(test)]
 mod tests {
+    use std::sync::Arc;
+
     use super::*;
-    use crate::{sync::Lrc, FileName, FilePathMapping, SourceMap};
+    use crate::{FileName, FilePathMapping, SourceMap};
 
-    fn with_test_sess<F>(src: &'static str, f: F)
+    fn with_test_sess<F>(src: &str, f: F)
     where
         F: FnOnce(StringInput<'_>),
     {
-        let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-        let fm = cm.new_source_file(FileName::Real("testing".into()).into(), src);
+        let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
+        let fm = cm.new_source_file(FileName::Real("testing".into()).into(), src.into());
 
         f((&*fm).into())
     }
--- a/crates/swc_common/src/source_map.rs
+++ b/crates/swc_common/src/source_map.rs
@@ -27,7 +27,6 @@
     sync::atomic::{AtomicUsize, Ordering::SeqCst},
 };
 
-use bytes_str::BytesStr;
 use once_cell::sync::Lazy;
 use rustc_hash::FxHashMap;
 #[cfg(feature = "sourcemap")]
@@ -56,7 +55,7 @@
     fn abs_path(&self, path: &Path) -> Option<PathBuf>;
 
     /// Read the contents of an UTF-8 file into memory.
-    fn read_file(&self, path: &Path) -> io::Result<BytesStr>;
+    fn read_file(&self, path: &Path) -> io::Result<String>;
 }
 
 /// A FileLoader that uses std::fs to load real files.
@@ -75,14 +74,8 @@
         }
     }
 
-    fn read_file(&self, path: &Path) -> io::Result<BytesStr> {
-        let bytes = fs::read(path)?;
-        BytesStr::from_utf8(bytes.into()).map_err(|_| {
-            io::Error::new(
-                io::ErrorKind::InvalidData,
-                "Failed to convert bytes to UTF-8",
-            )
-        })
+    fn read_file(&self, path: &Path) -> io::Result<String> {
+        fs::read_to_string(path)
     }
 }
 
@@ -212,21 +205,21 @@
 
     /// Creates a new source_file.
     /// This does not ensure that only one SourceFile exists per file name.
+    pub fn new_source_file(&self, filename: Lrc<FileName>, mut src: String) -> Lrc<SourceFile> {
+        remove_bom(&mut src);
+
+        self.new_source_file_from(filename, Lrc::new(src))
+    }
+
+    /// Creates a new source_file.
+    /// This does not ensure that only one SourceFile exists per file name.
     ///
-    /// - `src` should not have UTF8 BOM
-    /// - `&'static str` and [String] implements `Into<BytesStr>`
-    #[inline(always)]
-    pub fn new_source_file(
+    /// `src` should not have UTF8 BOM
+    pub fn new_source_file_from(
         &self,
         filename: Lrc<FileName>,
-        src: impl Into<BytesStr>,
+        src: Lrc<String>,
     ) -> Lrc<SourceFile> {
-        self.new_source_file_impl(filename, src.into())
-    }
-
-    fn new_source_file_impl(&self, filename: Lrc<FileName>, mut src: BytesStr) -> Lrc<SourceFile> {
-        remove_bom(&mut src);
-
         // The path is used to determine the directory for loading submodules and
         // include files, so it must be before remapping.
         // Note that filename may not be a valid path, eg it may be `<anon>` etc,
@@ -248,7 +241,7 @@
 
         let start_pos = self.next_start_pos(src.len());
 
-        let source_file = Lrc::new(SourceFile::new(
+        let source_file = Lrc::new(SourceFile::new_from(
             filename,
             was_remapped,
             unmapped_path,
@@ -1187,13 +1180,6 @@
     }
 }
 
-/// Remove utf-8 BOM if any.
-fn remove_bom(src: &mut BytesStr) {
-    if src.starts_with('\u{feff}') {
-        src.advance(3);
-    }
-}
-
 /// Calculates the number of excess chars seen in the UTF-8 encoding of a
 /// file compared with the UTF-16 encoding.
 fn calc_utf16_offset(file: &SourceFile, bpos: BytePos, state: &mut ByteToCharPosState) -> u32 {
@@ -1598,12 +1584,12 @@
         let sm = SourceMap::new(FilePathMapping::empty());
         sm.new_source_file(
             Lrc::new(PathBuf::from("blork.rs").into()),
-            "first line.\nsecond line",
+            "first line.\nsecond line".to_string(),
         );
-        sm.new_source_file(Lrc::new(PathBuf::from("empty.rs").into()), BytesStr::new());
+        sm.new_source_file(Lrc::new(PathBuf::from("empty.rs").into()), String::new());
         sm.new_source_file(
             Lrc::new(PathBuf::from("blork2.rs").into()),
-            "first line.\nsecond line",
+            "first line.\nsecond line".to_string(),
         );
         sm
     }
@@ -1659,11 +1645,11 @@
         // € is a three byte utf8 char.
         sm.new_source_file(
             Lrc::new(PathBuf::from("blork.rs").into()),
-            "fir€st €€€€ line.\nsecond line",
+            "fir€st €€€€ line.\nsecond line".to_string(),
         );
         sm.new_source_file(
             Lrc::new(PathBuf::from("blork2.rs").into()),
-            "first line€€.\n€ second line",
+            "first line€€.\n€ second line".to_string(),
         );
         sm
     }
@@ -1725,7 +1711,7 @@
         let selection = "     \n    ~~\n~~~\n~~~~~     \n   \n";
         sm.new_source_file(
             Lrc::new(Path::new("blork.rs").to_path_buf().into()),
-            inputtext,
+            inputtext.to_string(),
         );
         let span = span_from_selection(inputtext, selection);
 
@@ -1779,7 +1765,7 @@
     fn t10() {
         // Test span_to_lines for a span of empty file
         let sm = SourceMap::new(FilePathMapping::empty());
-        sm.new_source_file(Lrc::new(PathBuf::from("blork.rs").into()), "");
+        sm.new_source_file(Lrc::new(PathBuf::from("blork.rs").into()), "".to_string());
         let span = Span::new(BytePos(1), BytePos(1));
         let file_lines = sm.span_to_lines(span).unwrap();
 
@@ -1794,7 +1780,10 @@
         let inputtext = "bbbb BB\ncc CCC\n";
         let selection1 = "     ~~\n      \n";
         let selection2 = "       \n   ~~~\n";
-        sm.new_source_file(Lrc::new(Path::new("blork.rs").to_owned().into()), inputtext);
+        sm.new_source_file(
+            Lrc::new(Path::new("blork.rs").to_owned().into()),
+            inputtext.to_owned(),
+        );
         let span1 = span_from_selection(inputtext, selection1);
         let span2 = span_from_selection(inputtext, selection2);
 
@@ -1805,7 +1794,10 @@
     fn test_calc_utf16_offset() {
         let input = "t¢e∆s💩t";
         let sm = SourceMap::new(FilePathMapping::empty());
-        let file = sm.new_source_file(Lrc::new(PathBuf::from("blork.rs").into()), input);
+        let file = sm.new_source_file(
+            Lrc::new(PathBuf::from("blork.rs").into()),
+            input.to_string(),
+        );
 
         let mut state = ByteToCharPosState::default();
         let mut bpos = file.start_pos;
@@ -1833,7 +1825,10 @@
     fn bytepos_to_charpos() {
         let input = "t¢e∆s💩t";
         let sm = SourceMap::new(FilePathMapping::empty());
-        let file = sm.new_source_file(Lrc::new(PathBuf::from("blork.rs").into()), input);
+        let file = sm.new_source_file(
+            Lrc::new(PathBuf::from("blork.rs").into()),
+            input.to_string(),
+        );
 
         let mut bpos = file.start_pos;
         let mut cpos = CharPos(0);
--- a/crates/swc_common/src/syntax_pos.rs
+++ b/crates/swc_common/src/syntax_pos.rs
@@ -7,7 +7,6 @@
     sync::{atomic::AtomicU32, Mutex},
 };
 
-use bytes_str::BytesStr;
 use serde::{Deserialize, Serialize};
 use url::Url;
 
@@ -781,6 +780,57 @@
     }
 }
 
+/// This is not a public interface, workaround for https://github.com/swc-project/swc/issues/7238
+#[doc(hidden)]
+#[cfg(feature = "rkyv-impl")]
+#[derive(Debug, Clone, Copy)]
+#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
+#[cfg_attr(feature = "rkyv-impl", repr(C))]
+pub struct EncodeArcString;
+
+#[cfg(feature = "rkyv-impl")]
+impl rkyv::with::ArchiveWith<Lrc<String>> for EncodeArcString {
+    type Archived = rkyv::Archived<String>;
+    type Resolver = rkyv::Resolver<String>;
+
+    fn resolve_with(
+        field: &Lrc<String>,
+        resolver: Self::Resolver,
+        out: rkyv::Place<Self::Archived>,
+    ) {
+        let s = field.to_string();
+        rkyv::Archive::resolve(&s, resolver, out);
+    }
+}
+
+#[cfg(feature = "rkyv-impl")]
+impl<S> rkyv::with::SerializeWith<Lrc<String>, S> for EncodeArcString
+where
+    S: ?Sized + rancor::Fallible + rkyv::ser::Writer,
+    S::Error: rancor::Source,
+{
+    fn serialize_with(field: &Lrc<String>, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
+        rkyv::string::ArchivedString::serialize_from_str(field, serializer)
+    }
+}
+
+#[cfg(feature = "rkyv-impl")]
+impl<D> rkyv::with::DeserializeWith<rkyv::Archived<String>, Lrc<String>, D> for EncodeArcString
+where
+    D: ?Sized + rancor::Fallible,
+{
+    fn deserialize_with(
+        field: &rkyv::Archived<String>,
+        deserializer: &mut D,
+    ) -> Result<Lrc<String>, D::Error> {
+        use rkyv::Deserialize;
+
+        let s: String = field.deserialize(deserializer)?;
+
+        Ok(s.into())
+    }
+}
+
 /// A single source in the SourceMap.
 #[cfg_attr(
     any(feature = "rkyv-impl"),
@@ -803,7 +853,8 @@
     /// Indicates which crate this `SourceFile` was imported from.
     pub crate_of_origin: u32,
     /// The complete source code
-    pub src: BytesStr,
+    #[cfg_attr(any(feature = "rkyv-impl"), rkyv(with = EncodeArcString))]
+    pub src: Lrc<String>,
     /// The source code's hash
     pub src_hash: u128,
     /// The start position of this source in the `SourceMap`
@@ -839,12 +890,30 @@
 }
 
 impl SourceFile {
-    /// `src` should not have UTF8 BOM
     pub fn new(
         name: Lrc<FileName>,
         name_was_remapped: bool,
         unmapped_path: Lrc<FileName>,
-        src: BytesStr,
+        mut src: String,
+        start_pos: BytePos,
+    ) -> SourceFile {
+        remove_bom(&mut src);
+
+        Self::new_from(
+            name,
+            name_was_remapped,
+            unmapped_path,
+            Lrc::new(src),
+            start_pos,
+        )
+    }
+
+    /// `src` should not have UTF8 BOM
+    pub fn new_from(
+        name: Lrc<FileName>,
+        name_was_remapped: bool,
+        unmapped_path: Lrc<FileName>,
+        src: Lrc<String>,
         start_pos: BytePos,
     ) -> SourceFile {
         debug_assert_ne!(
@@ -975,6 +1044,13 @@
     }
 }
 
+/// Remove utf-8 BOM if any.
+pub(super) fn remove_bom(src: &mut String) {
+    if src.starts_with('\u{feff}') {
+        src.drain(..3);
+    }
+}
+
 // _____________________________________________________________________________
 // Pos, BytePos, CharPos
 //
--- a/crates/swc_error_reporters/examples/swc_try.rs
+++ b/crates/swc_error_reporters/examples/swc_try.rs
@@ -22,11 +22,11 @@
 
     let fm1 = cm.new_source_file(
         Lrc::new(FileName::Custom("foo.js".into())),
-        "13579\n12345\n13579",
+        "13579\n12345\n13579".into(),
     );
     let fm2 = cm.new_source_file(
         Lrc::new(FileName::Custom("bar.js".into())),
-        "02468\n12345\n02468",
+        "02468\n12345\n02468".into(),
     );
 
     // This is a simple example.
--- a/crates/swc_error_reporters/tests/fixture.rs
+++ b/crates/swc_error_reporters/tests/fixture.rs
@@ -35,7 +35,7 @@
 #[test]
 fn test_1() {
     output("1.ans", |cm, h| {
-        let _fm = cm.new_source_file(FileName::Anon.into(), "123456789");
+        let _fm = cm.new_source_file(FileName::Anon.into(), "123456789".into());
 
         h.struct_span_err(span(1, 3), "test")
             .span_label(span(1, 4), "label")
@@ -46,7 +46,7 @@
 #[test]
 fn test_2() {
     output("2.ans", |cm, h| {
-        let _fm = cm.new_source_file(FileName::Anon.into(), "123456789");
+        let _fm = cm.new_source_file(FileName::Anon.into(), "123456789".into());
 
         let mut d = h.struct_span_err(span(1, 3), "test");
 
@@ -65,7 +65,7 @@
 #[test]
 fn test_long_text_wrap() {
     output("long_text_wrap.ans", |cm, h| {
-        let _fm = cm.new_source_file(FileName::Anon.into(), "123456789");
+        let _fm = cm.new_source_file(FileName::Anon.into(), "123456789".into());
 
         let mut d = h.struct_span_err(span(1, 3), r##"You are attempting to export "metadata" from a component marked with "use client", which is disallowed. Either remove the export, or the "use client" directive. Read more: https://nextjs.org/docs/app/api-reference/directives/use-client"##);
 
