about summary refs log tree commit diff
path: root/src/librustdoc/html/render/ordered_json.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html/render/ordered_json.rs')
-rw-r--r--src/librustdoc/html/render/ordered_json.rs87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/librustdoc/html/render/ordered_json.rs b/src/librustdoc/html/render/ordered_json.rs
new file mode 100644
index 00000000000..3f76ff659d0
--- /dev/null
+++ b/src/librustdoc/html/render/ordered_json.rs
@@ -0,0 +1,87 @@
+use std::borrow::Borrow;
+use std::fmt;
+
+use itertools::Itertools as _;
+use serde::{Deserialize, Serialize};
+use serde_json::Value;
+
+/// Prerenedered json.
+///
+/// Both the Display and serde_json::to_string implementations write the serialized json
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
+#[serde(from = "Value")]
+#[serde(into = "Value")]
+pub(crate) struct OrderedJson(String);
+
+impl OrderedJson {
+    /// If you pass in an array, it will not be sorted.
+    pub(crate) fn serialize<T: Serialize>(item: T) -> Result<Self, serde_json::Error> {
+        Ok(OrderedJson(serde_json::to_string(&item)?))
+    }
+
+    /// Serializes and sorts
+    pub(crate) fn array_sorted<T: Borrow<OrderedJson>, I: IntoIterator<Item = T>>(
+        items: I,
+    ) -> Self {
+        let items = items
+            .into_iter()
+            .sorted_unstable_by(|a, b| a.borrow().cmp(&b.borrow()))
+            .format_with(",", |item, f| f(item.borrow()));
+        OrderedJson(format!("[{}]", items))
+    }
+
+    pub(crate) fn array_unsorted<T: Borrow<OrderedJson>, I: IntoIterator<Item = T>>(
+        items: I,
+    ) -> Self {
+        let items = items.into_iter().format_with(",", |item, f| f(item.borrow()));
+        OrderedJson(format!("[{items}]"))
+    }
+}
+
+impl fmt::Display for OrderedJson {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl From<Value> for OrderedJson {
+    fn from(value: Value) -> Self {
+        let serialized =
+            serde_json::to_string(&value).expect("Serializing a Value to String should never fail");
+        OrderedJson(serialized)
+    }
+}
+
+impl From<OrderedJson> for Value {
+    fn from(json: OrderedJson) -> Self {
+        serde_json::from_str(&json.0).expect("OrderedJson should always store valid JSON")
+    }
+}
+
+/// For use in JSON.parse('{...}').
+///
+/// Assumes we are going to be wrapped in single quoted strings.
+///
+/// JSON.parse loads faster than raw JS source,
+/// so this is used for large objects.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub(crate) struct EscapedJson(OrderedJson);
+
+impl From<OrderedJson> for EscapedJson {
+    fn from(json: OrderedJson) -> Self {
+        EscapedJson(json)
+    }
+}
+
+impl fmt::Display for EscapedJson {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // All these `replace` calls are because we have to go through JS string
+        // for JSON content.
+        // We need to escape double quotes for the JSON
+        let json = self.0.0.replace('\\', r"\\").replace('\'', r"\'").replace("\\\"", "\\\\\"");
+        json.fmt(f)
+    }
+}
+
+#[cfg(test)]
+mod tests;