From 3232fb7eca0ec503fe922b87af648ed4eea88e77 Mon Sep 17 00:00:00 2001
From: Chris Wong <lambda.fairy@gmail.com>
Date: Sat, 6 Nov 2021 22:33:44 +1100
Subject: [PATCH] Delete `maud_htmlescape` package (#311)

Replace it with a symlink. Cargo will automatically resolve this to a
normal file on publish.
---
 Cargo.toml                  |   1 -
 RELEASE_PROCESS.md          |   2 -
 docs/Cargo.lock             | 105 +++++++++++++++++++++++++++---------
 maud/Cargo.toml             |   1 -
 maud/src/escape.rs          |  30 +++++++++++
 maud/src/lib.rs             |  45 ++++++++++++++--
 maud_htmlescape/Cargo.toml  |  14 -----
 maud_htmlescape/lib.rs      |  73 -------------------------
 maud_macros/Cargo.toml      |   1 -
 maud_macros/src/escape.rs   |   1 +
 maud_macros/src/generate.rs |   6 +--
 maud_macros/src/lib.rs      |   1 +
 12 files changed, 154 insertions(+), 126 deletions(-)
 create mode 100644 maud/src/escape.rs
 delete mode 100644 maud_htmlescape/Cargo.toml
 delete mode 100644 maud_htmlescape/lib.rs
 create mode 120000 maud_macros/src/escape.rs

diff --git a/Cargo.toml b/Cargo.toml
index 1631727..5a930f9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,5 @@
 [workspace]
 members = [
-    "maud_htmlescape",
     "maud_macros",
     "maud",
 ]
diff --git a/RELEASE_PROCESS.md b/RELEASE_PROCESS.md
index d5e751d..906354b 100644
--- a/RELEASE_PROCESS.md
+++ b/RELEASE_PROCESS.md
@@ -4,11 +4,9 @@
 2. Update `Cargo.toml`:
     - [`maud`](maud/Cargo.toml) (don't forget dependencies!)
     - [`maud_macros`](maud_macros/Cargo.toml)
-    - [`maud_htmlescape`](maud_htmlescape/Cargo.toml) (if necessary)
 3. Update `#![doc(html_root_html = "...")]`:
     - [`maud`](maud/src/lib.rs)
     - [`maud_macros`](maud_macros/src/lib.rs)
-    - [`maud_htmlescape`](maud_htmlescape/src/lib.rs) (if necessary)
 4. `cd docs && cargo update`
 5. Commit to a new branch `release-X.Y.Z`, open a PR, fix issues, merge
 6. [Create a release](https://github.com/lambda-fairy/maud/releases/new)
diff --git a/docs/Cargo.lock b/docs/Cargo.lock
index 0eb110f..a450f6a 100644
--- a/docs/Cargo.lock
+++ b/docs/Cargo.lock
@@ -99,9 +99,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
 [[package]]
 name = "cc"
-version = "1.0.70"
+version = "1.0.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
+checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
 
 [[package]]
 name = "cfg-if"
@@ -172,6 +172,26 @@ dependencies = [
  "generic-array",
 ]
 
+[[package]]
+name = "dirs"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
 [[package]]
 name = "docs"
 version = "0.0.0"
@@ -221,6 +241,17 @@ dependencies = [
  "typenum",
 ]
 
+[[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
 [[package]]
 name = "hashbrown"
 version = "0.11.2"
@@ -266,9 +297,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.102"
+version = "0.2.106"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
+checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673"
 
 [[package]]
 name = "line-wrap"
@@ -295,19 +326,13 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
 name = "maud"
 version = "0.22.3"
 dependencies = [
- "maud_htmlescape",
  "maud_macros",
 ]
 
-[[package]]
-name = "maud_htmlescape"
-version = "0.17.1"
-
 [[package]]
 name = "maud_macros"
 version = "0.22.3"
 dependencies = [
- "maud_htmlescape",
  "proc-macro-error",
  "proc-macro2",
  "quote",
@@ -351,9 +376,9 @@ dependencies = [
 
 [[package]]
 name = "onig"
-version = "6.2.0"
+version = "6.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b16fd3c0e73b516af509c13c4ba76ec0c987ce20d78b38cff356b8d01fc6a6c0"
+checksum = "67ddfe2c93bb389eea6e6d713306880c7f6dcc99a75b659ce145d962c861b225"
 dependencies = [
  "bitflags",
  "lazy_static",
@@ -363,9 +388,9 @@ dependencies = [
 
 [[package]]
 name = "onig_sys"
-version = "69.7.0"
+version = "69.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fd9442a09e4fbd08d196ddf419b2c79a43c3a46c800320cc841d45c2449a240"
+checksum = "5dd3eee045c84695b53b20255bb7317063df090b68e18bfac0abb6c39cf7f33e"
 dependencies = [
  "cc",
  "pkg-config",
@@ -422,9 +447,9 @@ dependencies = [
 
 [[package]]
 name = "pkg-config"
-version = "0.3.20"
+version = "0.3.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb"
+checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
 
 [[package]]
 name = "plist"
@@ -466,22 +491,41 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.29"
+version = "1.0.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
+checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
 dependencies = [
  "unicode-xid",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.9"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
 dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "redox_syscall"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
+dependencies = [
+ "getrandom",
+ "redox_syscall",
+]
+
 [[package]]
 name = "regex"
 version = "1.5.4"
@@ -539,9 +583,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.68"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
+checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
 dependencies = [
  "itoa",
  "ryu",
@@ -574,9 +618,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
 
 [[package]]
 name = "syn"
-version = "1.0.77"
+version = "1.0.81"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0"
+checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -689,6 +733,12 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
 [[package]]
 name = "winapi"
 version = "0.3.9"
@@ -722,9 +772,12 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "xdg"
-version = "2.2.0"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
+checksum = "3a23fe958c70412687039c86f578938b4a0bb50ec788e96bce4d6ab00ddd5803"
+dependencies = [
+ "dirs",
+]
 
 [[package]]
 name = "xml-rs"
diff --git a/maud/Cargo.toml b/maud/Cargo.toml
index 7e71039..7229866 100644
--- a/maud/Cargo.toml
+++ b/maud/Cargo.toml
@@ -18,7 +18,6 @@ default = []
 actix-web = ["actix-web-dep", "futures-util"]
 
 [dependencies]
-maud_htmlescape = { version = "0.17.1", path = "../maud_htmlescape" }
 maud_macros = { version = "0.22.3", path = "../maud_macros" }
 iron = { version = ">= 0.5.1, < 0.7.0", optional = true }
 rocket = { version = ">= 0.3, < 0.5", optional = true }
diff --git a/maud/src/escape.rs b/maud/src/escape.rs
new file mode 100644
index 0000000..f5c24d2
--- /dev/null
+++ b/maud/src/escape.rs
@@ -0,0 +1,30 @@
+extern crate alloc;
+
+use alloc::string::String;
+
+pub fn escape_to_string(input: &str, output: &mut String) {
+    for b in input.bytes() {
+        match b {
+            b'&' => output.push_str("&amp;"),
+            b'<' => output.push_str("&lt;"),
+            b'>' => output.push_str("&gt;"),
+            b'"' => output.push_str("&quot;"),
+            _ => unsafe { output.as_mut_vec().push(b) },
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    extern crate alloc;
+
+    use super::escape_to_string;
+    use alloc::string::String;
+
+    #[test]
+    fn it_works() {
+        let mut s = String::new();
+        escape_to_string("<script>launchMissiles()</script>", &mut s);
+        assert_eq!(s, "&lt;script&gt;launchMissiles()&lt;/script&gt;");
+    }
+}
diff --git a/maud/src/lib.rs b/maud/src/lib.rs
index cca9ff7..b39cd22 100644
--- a/maud/src/lib.rs
+++ b/maud/src/lib.rs
@@ -16,6 +16,46 @@ use core::fmt::{self, Write};
 
 pub use maud_macros::{html, html_debug};
 
+mod escape;
+
+/// An adapter that escapes HTML special characters.
+///
+/// The following characters are escaped:
+///
+/// * `&` is escaped as `&amp;`
+/// * `<` is escaped as `&lt;`
+/// * `>` is escaped as `&gt;`
+/// * `"` is escaped as `&quot;`
+///
+/// All other characters are passed through unchanged.
+///
+/// **Note:** In versions prior to 0.13, the single quote (`'`) was
+/// escaped as well.
+///
+/// # Example
+///
+/// ```rust,ignore
+/// use std::fmt::Write;
+/// let mut s = String::new();
+/// write!(Escaper::new(&mut s), "<script>launchMissiles()</script>").unwrap();
+/// assert_eq!(s, "&lt;script&gt;launchMissiles()&lt;/script&gt;");
+/// ```
+pub struct Escaper<'a>(&'a mut String);
+
+impl<'a> Escaper<'a> {
+    /// Creates an `Escaper` from a `String`.
+    pub fn new(buffer: &'a mut String) -> Escaper<'a> {
+        Escaper(buffer)
+    }
+}
+
+impl<'a> fmt::Write for Escaper<'a> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        escape::escape_to_string(s, self.0);
+        Ok(())
+    }
+}
+
 /// Represents a type that can be rendered as HTML.
 ///
 /// If your type implements [`Display`][1], then it will implement this
@@ -93,10 +133,9 @@ impl<T: fmt::Display + ?Sized> Render for T {
 /// [1]: https://github.com/dtolnay/case-studies/issues/14
 #[doc(hidden)]
 pub mod render {
-    use crate::Render;
+    use crate::{Escaper, Render};
     use alloc::string::String;
     use core::fmt::Write;
-    use maud_htmlescape::Escaper;
 
     pub trait RenderInternal {
         fn __maud_render_to(&self, w: &mut String);
@@ -145,8 +184,6 @@ impl<T: AsRef<str> + Into<String>> From<PreEscaped<T>> for String {
     }
 }
 
-pub use maud_htmlescape::Escaper;
-
 /// The literal string `<!DOCTYPE html>`.
 ///
 /// # Example
diff --git a/maud_htmlescape/Cargo.toml b/maud_htmlescape/Cargo.toml
deleted file mode 100644
index 82514fb..0000000
--- a/maud_htmlescape/Cargo.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-[package]
-name = "maud_htmlescape"
-# When releasing a new version, please update html_root_url in lib.rs
-version = "0.17.1"
-authors = ["Chris Wong <lambda.fairy@gmail.com>"]
-license = "MIT/Apache-2.0"
-documentation = "https://docs.rs/maud_htmlescape/"
-homepage = "https://maud.lambda.xyz/"
-repository = "https://github.com/lambda-fairy/maud"
-description = "Internal support code used by Maud."
-edition = "2021"
-
-[lib]
-path = "lib.rs"
diff --git a/maud_htmlescape/lib.rs b/maud_htmlescape/lib.rs
deleted file mode 100644
index f8adb77..0000000
--- a/maud_htmlescape/lib.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-#![cfg_attr(not(test), no_std)]
-
-//! Internal support code used by the [Maud] template engine.
-//!
-//! You should not need to depend on this crate directly.
-//!
-//! [Maud]: https://maud.lambda.xyz
-
-#![doc(html_root_url = "https://docs.rs/maud_htmlescape/0.17.1")]
-
-extern crate alloc;
-
-use alloc::string::String;
-use core::fmt;
-
-/// An adapter that escapes HTML special characters.
-///
-/// The following characters are escaped:
-///
-/// * `&` is escaped as `&amp;`
-/// * `<` is escaped as `&lt;`
-/// * `>` is escaped as `&gt;`
-/// * `"` is escaped as `&quot;`
-///
-/// All other characters are passed through unchanged.
-///
-/// **Note:** In versions prior to 0.13, the single quote (`'`) was
-/// escaped as well.
-///
-/// # Example
-///
-/// ```rust,ignore
-/// use std::fmt::Write;
-/// let mut s = String::new();
-/// write!(Escaper::new(&mut s), "<script>launchMissiles()</script>").unwrap();
-/// assert_eq!(s, "&lt;script&gt;launchMissiles()&lt;/script&gt;");
-/// ```
-pub struct Escaper<'a>(&'a mut String);
-
-impl<'a> Escaper<'a> {
-    /// Creates an `Escaper` from a `String`.
-    pub fn new(buffer: &'a mut String) -> Escaper<'a> {
-        Escaper(buffer)
-    }
-}
-
-impl<'a> fmt::Write for Escaper<'a> {
-    fn write_str(&mut self, s: &str) -> fmt::Result {
-        for b in s.bytes() {
-            match b {
-                b'&' => self.0.push_str("&amp;"),
-                b'<' => self.0.push_str("&lt;"),
-                b'>' => self.0.push_str("&gt;"),
-                b'"' => self.0.push_str("&quot;"),
-                _ => unsafe { self.0.as_mut_vec().push(b) },
-            }
-        }
-        Ok(())
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use crate::Escaper;
-    use std::fmt::Write;
-
-    #[test]
-    fn it_works() {
-        let mut s = String::new();
-        write!(Escaper::new(&mut s), "<script>launchMissiles()</script>").unwrap();
-        assert_eq!(s, "&lt;script&gt;launchMissiles()&lt;/script&gt;");
-    }
-}
diff --git a/maud_macros/Cargo.toml b/maud_macros/Cargo.toml
index 7e18d51..14a2f5c 100644
--- a/maud_macros/Cargo.toml
+++ b/maud_macros/Cargo.toml
@@ -12,7 +12,6 @@ edition = "2021"
 
 [dependencies]
 syn = "1.0.8"
-maud_htmlescape = { version = "0.17.0", path = "../maud_htmlescape" }
 quote = "1.0.7"
 proc-macro2 = "1.0.23"
 proc-macro-error = "1.0.0"
diff --git a/maud_macros/src/escape.rs b/maud_macros/src/escape.rs
new file mode 120000
index 0000000..fc68ead
--- /dev/null
+++ b/maud_macros/src/escape.rs
@@ -0,0 +1 @@
+../../maud/src/escape.rs
\ No newline at end of file
diff --git a/maud_macros/src/generate.rs b/maud_macros/src/generate.rs
index ff5729a..1f4ee99 100644
--- a/maud_macros/src/generate.rs
+++ b/maud_macros/src/generate.rs
@@ -1,9 +1,8 @@
-use maud_htmlescape::Escaper;
 use proc_macro2::{Delimiter, Group, Ident, Literal, Span, TokenStream, TokenTree};
 use proc_macro_error::SpanRange;
 use quote::quote;
 
-use crate::ast::*;
+use crate::{ast::*, escape};
 
 pub fn generate(markups: Vec<Markup>, output_ident: TokenTree) -> TokenStream {
     let mut build = Builder::new(output_ident.clone());
@@ -271,8 +270,7 @@ impl Builder {
     }
 
     fn push_escaped(&mut self, string: &str) {
-        use std::fmt::Write;
-        Escaper::new(&mut self.tail).write_str(string).unwrap();
+        escape::escape_to_string(string, &mut self.tail);
     }
 
     fn push_tokens(&mut self, tokens: TokenStream) {
diff --git a/maud_macros/src/lib.rs b/maud_macros/src/lib.rs
index 4be664e..35f05f3 100644
--- a/maud_macros/src/lib.rs
+++ b/maud_macros/src/lib.rs
@@ -6,6 +6,7 @@
 extern crate proc_macro;
 
 mod ast;
+mod escape;
 mod generate;
 mod parse;