malachite_base/maps/typst.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::strings::typst::ToTypst;
10#[cfg(not(feature = "std"))]
11use alloc::collections::BTreeMap;
12use alloc::vec::Vec;
13use core::fmt::{Formatter, Result};
14use core::hash::Hash;
15#[cfg(not(feature = "std"))]
16use hashbrown::HashMap;
17#[cfg(feature = "std")]
18use std::collections::{BTreeMap, HashMap};
19
20// Writes a sequence of entries as one braced, comma-separated Typst math-mode fragment, each
21// entry's key and value joined by a "maps to" arrow.
22fn fmt_typst_entries<'a, K: ToTypst + 'a, V: ToTypst + 'a>(
23 entries: impl Iterator<Item = (&'a K, &'a V)>,
24 f: &mut Formatter,
25) -> Result {
26 f.write_str("{")?;
27 for (i, (k, v)) in entries.enumerate() {
28 if i != 0 {
29 f.write_str(", ")?;
30 }
31 k.fmt_typst(f)?;
32 f.write_str(" |-> ")?;
33 v.fmt_typst(f)?;
34 }
35 f.write_str("}")
36}
37
38impl<K: ToTypst, V: ToTypst> ToTypst for BTreeMap<K, V> {
39 /// Writes a [`BTreeMap`] as a LaTeX math-mode fragment.
40 ///
41 /// Each entry is written as its key, a "maps to" arrow, and its value; the entries are
42 /// separated by commas and wrapped in braces, as a map is a set of associations. The entries
43 /// come in the map's own order, which is ascending by key.
44 ///
45 /// Typst grows a matched pair of delimiters to fit what is between them, so the braces fit an
46 /// entry that is taller than one line without being asked to. An empty map becomes `{}` rather
47 /// than nothing at all.
48 ///
49 /// # Worst-case complexity
50 /// $T(n) = O(n + \sum_{i=0}^{n-1}(T^\prime(i) + T^{\prime\prime}(i)))$
51 ///
52 /// $M(n) = O(\max_{i=0}^{n-1}(M^\prime(i) + M^{\prime\prime}(i)))$
53 ///
54 /// where $T$ is time, $M$ is additional memory, $n$ is `self.len()`, $i$ is an entry's index,
55 /// $T^\prime$ and $M^\prime$ are the time and memory functions of `fmt_typst` for `K`, and
56 /// $T^{\prime\prime}$ and $M^{\prime\prime}$ are those for `V`.
57 ///
58 /// # Examples
59 /// ```
60 /// use malachite_base::strings::typst::ToTypst;
61 /// use std::collections::BTreeMap;
62 ///
63 /// let empty = BTreeMap::<u8, u8>::new();
64 /// assert_eq!(empty.to_typst_string(), "{}");
65 ///
66 /// let m = BTreeMap::from([(2u8, 20u8), (1, 10)]);
67 /// assert_eq!(m.to_typst_string(), "{1 |-> 10, 2 |-> 20}");
68 /// ```
69 ///
70 /// | value | fragment |
71 /// |------------------------------------------|--------------------------|
72 /// | `BTreeMap::<u8, u8>::new()` | `{}` |
73 /// | `BTreeMap::from([(2u8, 20u8), (1, 10)])` | `{1 \|-> 10, 2 \|-> 20}` |
74 #[inline]
75 fn fmt_typst(&self, f: &mut Formatter) -> Result {
76 fmt_typst_entries(self.iter(), f)
77 }
78}
79
80impl<K: Eq + Hash + Ord + ToTypst, V: ToTypst> ToTypst for HashMap<K, V> {
81 /// Writes a [`HashMap`] as a LaTeX math-mode fragment.
82 ///
83 /// Each entry is written as its key, a "maps to" arrow, and its value; the entries are
84 /// separated by commas and wrapped in braces, as a map is a set of associations.
85 ///
86 /// The entries are sorted by key first, which is why this asks for [`Ord`] where a [`HashMap`]
87 /// does not. A [`HashMap`] iterates in an order that depends on its hasher, so without sorting
88 /// two equal maps could have different fragments, and the same map could have a different
89 /// fragment in the next run. Sorting also makes a [`HashMap`]'s fragment agree with the
90 /// [`BTreeMap`] of the same entries.
91 ///
92 /// Typst grows a matched pair of delimiters to fit what is between them, so the braces fit an
93 /// entry that is taller than one line without being asked to. An empty map becomes `{}` rather
94 /// than nothing at all.
95 ///
96 /// # Worst-case complexity
97 /// $T(n) = O(n \log n + \sum_{i=0}^{n-1}(T^\prime(i) + T^{\prime\prime}(i)))$
98 ///
99 /// $M(n) = O(n + \max_{i=0}^{n-1}(M^\prime(i) + M^{\prime\prime}(i)))$
100 ///
101 /// where $T$ is time, $M$ is additional memory, $n$ is `self.len()`, $i$ is an entry's index,
102 /// $T^\prime$ and $M^\prime$ are the time and memory functions of `fmt_typst` for `K`, and
103 /// $T^{\prime\prime}$ and $M^{\prime\prime}$ are those for `V`.
104 ///
105 /// # Examples
106 /// ```
107 /// use malachite_base::strings::typst::ToTypst;
108 /// use std::collections::HashMap;
109 ///
110 /// let empty = HashMap::<u8, u8>::new();
111 /// assert_eq!(empty.to_typst_string(), "{}");
112 ///
113 /// // The entries are sorted by key, so the fragment does not depend on the hasher.
114 /// let m = HashMap::from([(2u8, 20u8), (1, 10)]);
115 /// assert_eq!(m.to_typst_string(), "{1 |-> 10, 2 |-> 20}");
116 /// ```
117 ///
118 /// | value | fragment |
119 /// |-----------------------------------------|--------------------------|
120 /// | `HashMap::<u8, u8>::new()` | `{}` |
121 /// | `HashMap::from([(2u8, 20u8), (1, 10)])` | `{1 \|-> 10, 2 \|-> 20}` |
122 fn fmt_typst(&self, f: &mut Formatter) -> Result {
123 let mut entries = self.iter().collect::<Vec<_>>();
124 entries.sort_unstable_by_key(|&(k, _)| k);
125 fmt_typst_entries(entries.into_iter(), f)
126 }
127}