Skip to main content

map_to_javascript_html/maps/
serde_json_map.rs

1use alloc::{string::String, vec::Vec};
2use core::{borrow::Borrow, fmt::Display, hash::Hash, str::from_utf8_unchecked};
3#[cfg(feature = "std")]
4use std::io::{self, Write};
5
6use serde_json::{Map, Value};
7
8#[cfg(feature = "std")]
9use crate::encode::{encode_display_to_writer, encode_serializable_to_writer};
10use crate::{
11    encode::{encode_display_to_vec, encode_serializable_to_vec},
12    MapToJavaScriptHTML,
13};
14
15#[inline]
16fn value_to_javascript_value_end_with_semicolon_in_html_to_vec(
17    value: &Value,
18    scratch: &mut Vec<u8>,
19    output: &mut Vec<u8>,
20) {
21    encode_serializable_to_vec(value, scratch, output);
22    output.push(b';');
23}
24
25#[cfg(feature = "std")]
26#[inline]
27fn value_to_javascript_value_end_with_semicolon_in_html_to_writer<W: Write>(
28    value: &Value,
29    scratch: &mut Vec<u8>,
30    output: &mut W,
31) -> Result<(), io::Error> {
32    encode_serializable_to_writer(value, scratch, output)?;
33    output.write_all(b";")
34}
35
36impl MapToJavaScriptHTML<String> for Map<String, Value> {
37    fn to_javascript_html_to_vec<'a, S: Display>(
38        &self,
39        variable_name: S,
40        output: &'a mut Vec<u8>,
41    ) -> &'a [u8] {
42        let variable_name = format!("{}", variable_name);
43
44        let current_length = output.len();
45
46        output.reserve((variable_name.len() + 11) * self.len());
47        let mut scratch = Vec::new();
48
49        for (key, value) in self {
50            output.extend_from_slice(variable_name.as_bytes());
51            output.push(b'[');
52            encode_display_to_vec(key, &mut scratch, output);
53            output.extend_from_slice(b"]=");
54            value_to_javascript_value_end_with_semicolon_in_html_to_vec(
55                value,
56                &mut scratch,
57                output,
58            );
59        }
60
61        &output[current_length..]
62    }
63
64    #[inline]
65    fn to_javascript_html_to_string<'a, S: Display>(
66        &self,
67        variable_name: S,
68        output: &'a mut String,
69    ) -> &'a str {
70        // SAFETY: This implementation only appends UTF-8 produced by formatting, serde_json, and ASCII constants.
71        unsafe {
72            from_utf8_unchecked(self.to_javascript_html_to_vec(variable_name, output.as_mut_vec()))
73        }
74    }
75
76    #[cfg(feature = "std")]
77    fn to_javascript_html_to_writer<S: Display, W: Write>(
78        &self,
79        variable_name: S,
80        output: &mut W,
81    ) -> Result<(), io::Error> {
82        let variable_name = format!("{}", variable_name);
83        let mut scratch = Vec::new();
84
85        for (key, value) in self {
86            output.write_all(variable_name.as_bytes())?;
87            output.write_all(b"[")?;
88            encode_display_to_writer(key, &mut scratch, output)?;
89            output.write_all(b"]=")?;
90            value_to_javascript_value_end_with_semicolon_in_html_to_writer(
91                value,
92                &mut scratch,
93                output,
94            )?;
95        }
96
97        Ok(())
98    }
99
100    #[inline]
101    fn to_javascript_html_with_keys_to_vec<'a, S: Display, KS: ?Sized + Display + Ord + Hash>(
102        &self,
103        variable_name: S,
104        keys: &[&KS],
105        output: &'a mut Vec<u8>,
106    ) -> &'a [u8]
107    where
108        String: Borrow<KS>, {
109        let variable_name = format!("{}", variable_name);
110
111        let current_length = output.len();
112
113        output.reserve((variable_name.len() + 11) * keys.len());
114        let mut scratch = Vec::new();
115
116        for key in keys {
117            output.extend_from_slice(variable_name.as_bytes());
118            output.push(b'[');
119            encode_display_to_vec(*key, &mut scratch, output);
120            output.extend_from_slice(b"]=");
121            match self.get(key) {
122                Some(value) => {
123                    value_to_javascript_value_end_with_semicolon_in_html_to_vec(
124                        value,
125                        &mut scratch,
126                        output,
127                    );
128                },
129                None => {
130                    output.extend_from_slice(b"undefined;");
131                },
132            }
133        }
134
135        &output[current_length..]
136    }
137
138    #[inline]
139    fn to_javascript_html_with_keys_to_string<
140        'a,
141        S: Display,
142        KS: ?Sized + Display + Ord + Eq + Hash,
143    >(
144        &self,
145        variable_name: S,
146        keys: &[&KS],
147        output: &'a mut String,
148    ) -> &'a str
149    where
150        String: Borrow<KS>, {
151        // SAFETY: This implementation only appends UTF-8 produced by formatting, serde_json, and ASCII constants.
152        unsafe {
153            from_utf8_unchecked(self.to_javascript_html_with_keys_to_vec(
154                variable_name,
155                keys,
156                output.as_mut_vec(),
157            ))
158        }
159    }
160
161    #[cfg(feature = "std")]
162    fn to_javascript_html_with_keys_to_writer<
163        S: Display,
164        W: Write,
165        KS: ?Sized + Display + Ord + Hash,
166    >(
167        &self,
168        variable_name: S,
169        keys: &[&KS],
170        output: &mut W,
171    ) -> Result<(), io::Error>
172    where
173        String: Borrow<KS>, {
174        let variable_name = format!("{}", variable_name);
175        let mut scratch = Vec::new();
176
177        for key in keys {
178            output.write_all(variable_name.as_bytes())?;
179            output.write_all(b"[")?;
180            encode_display_to_writer(*key, &mut scratch, output)?;
181            output.write_all(b"]=")?;
182            match self.get(key) {
183                Some(value) => {
184                    value_to_javascript_value_end_with_semicolon_in_html_to_writer(
185                        value,
186                        &mut scratch,
187                        output,
188                    )?;
189                },
190                None => {
191                    output.write_all(b"undefined;")?;
192                },
193            }
194        }
195
196        Ok(())
197    }
198}