1 // Copyright 2015-2016 Mozilla Foundation. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9 
10 #pragma once
11 
12 #ifndef encoding_rs_mem_cpp_h_
13 #define encoding_rs_mem_cpp_h_
14 
15 #include <optional>
16 #include <string_view>
17 #include <tuple>
18 #include "gsl/gsl"
19 
20 #include "encoding_rs_mem.h"
21 
22 namespace encoding_rs {
23 namespace mem {
24 
25 namespace detail {
26 /**
27  * Replaces `nullptr` with a bogus pointer suitable for use as part of a
28  * zero-length Rust slice.
29  */
30 template <class T>
null_to_bogus(T * ptr)31 static inline T* null_to_bogus(T* ptr) {
32   return ptr ? ptr : reinterpret_cast<T*>(alignof(T));
33 }
34 };  // namespace detail
35 
36 /**
37  * Checks whether a potentially invalid UTF-16 buffer contains code points
38  * that trigger right-to-left processing or is all-Latin1.
39  *
40  * Possibly more efficient than performing the checks separately.
41  *
42  * Returns `Latin1Bidi::Latin1` if `is_utf16_latin1()` would return `true`.
43  * Otherwise, returns `Latin1Bidi::Bidi` if `is_utf16_bidi()` would return
44  * `true`. Otherwise, returns `Latin1Bidi::LeftToRight`.
45  */
check_for_latin1_and_bidi(std::u16string_view buffer)46 inline Latin1Bidi check_for_latin1_and_bidi(std::u16string_view buffer) {
47   return encoding_mem_check_utf16_for_latin1_and_bidi(
48       encoding_rs::mem::detail::null_to_bogus<const char16_t>(buffer.data()),
49       buffer.size());
50 }
51 
52 /**
53  * Checks whether a potentially invalid UTF-8 buffer contains code points
54  * that trigger right-to-left processing or is all-Latin1.
55  *
56  * Possibly more efficient than performing the checks separately.
57  *
58  * Returns `Latin1Bidi::Latin1` if `is_utf8_latin1()` would return `true`.
59  *
60  * Otherwise, returns `Latin1Bidi::Bidi` if `is_utf8_bidi()` would return
61  * `true`. Otherwise, returns `Latin1Bidi::LeftToRight`.
62  */
check_for_latin1_and_bidi(std::string_view buffer)63 inline Latin1Bidi check_for_latin1_and_bidi(std::string_view buffer) {
64   return encoding_mem_check_utf8_for_latin1_and_bidi(
65       encoding_rs::mem::detail::null_to_bogus<const char>(buffer.data()),
66       buffer.size());
67 }
68 
69 /**
70  * Converts bytes whose unsigned value is interpreted as Unicode code point
71  * (i.e. U+0000 to U+00FF, inclusive) to UTF-16.
72  *
73  * The length of the destination buffer must be at least the length of the
74  * source buffer.
75  *
76  * The number of `char16_t`s written equals the length of the source buffer.
77  *
78  * # Panics
79  *
80  * Panics if the destination buffer is shorter than stated above.
81  */
convert_latin1_to_utf16(gsl::span<const char> src,gsl::span<char16_t> dst)82 inline void convert_latin1_to_utf16(gsl::span<const char> src,
83                                     gsl::span<char16_t> dst) {
84   encoding_mem_convert_latin1_to_utf16(
85       encoding_rs::mem::detail::null_to_bogus<const char>(src.data()),
86       src.size(), encoding_rs::mem::detail::null_to_bogus<char16_t>(dst.data()),
87       dst.size());
88 }
89 
90 /**
91  * Converts bytes whose unsigned value is interpreted as Unicode code point
92  * (i.e. U+0000 to U+00FF, inclusive) to UTF-8.
93  *
94  * The length of the destination buffer must be at least the length of the
95  * source buffer times two.
96  *
97  * Returns the number of bytes written.
98  *
99  * # Panics
100  *
101  * Panics if the destination buffer is shorter than stated above.
102  *
103  * # Safety
104  *
105  * Note that this function may write garbage beyond the number of bytes
106  * indicated by the return value.
107  *
108  * # Undefined behavior
109  *
110  * UB ensues if `src` and `dst` overlap.
111  */
convert_latin1_to_utf8(gsl::span<const char> src,gsl::span<char> dst)112 inline size_t convert_latin1_to_utf8(gsl::span<const char> src,
113                                      gsl::span<char> dst) {
114   return encoding_mem_convert_latin1_to_utf8(
115       encoding_rs::mem::detail::null_to_bogus<const char>(src.data()),
116       src.size(), encoding_rs::mem::detail::null_to_bogus<char>(dst.data()),
117       dst.size());
118 }
119 
120 /**
121  * Converts bytes whose unsigned value is interpreted as Unicode code point
122  * (i.e. U+0000 to U+00FF, inclusive) to UTF-8 with potentially insufficient
123  * output space.
124  *
125  * Returns the number of bytes read and the number of bytes written.
126  *
127  * If the output isn't large enough, not all input is consumed.
128  *
129  * # Undefined behavior
130  *
131  * UB ensues if `src` and `dst` overlap.
132  */
convert_latin1_to_utf8_partial(gsl::span<const char> src,gsl::span<char> dst)133 inline std::tuple<size_t, size_t> convert_latin1_to_utf8_partial(
134     gsl::span<const char> src, gsl::span<char> dst) {
135   size_t src_read = src.size();
136   size_t dst_written = dst.size();
137   encoding_mem_convert_latin1_to_utf8_partial(
138       encoding_rs::mem::detail::null_to_bogus<const char>(src.data()),
139       &src_read, encoding_rs::mem::detail::null_to_bogus<char>(dst.data()),
140       &dst_written);
141   return {src_read, dst_written};
142 }
143 
144 /**
145  * Converts valid UTF-8 to valid UTF-16.
146  *
147  * The length of the destination buffer must be at least the length of the
148  * source buffer.
149  *
150  * Returns the number of `char16_t`s written.
151  *
152  * # Panics
153  *
154  * Panics if the destination buffer is shorter than stated above.
155  */
convert_str_to_utf16(std::string_view src,gsl::span<char16_t> dst)156 inline size_t convert_str_to_utf16(std::string_view src,
157                                    gsl::span<char16_t> dst) {
158   return encoding_mem_convert_str_to_utf16(
159       encoding_rs::mem::detail::null_to_bogus<const char>(
160           reinterpret_cast<const char*>(src.data())),
161       src.size(), encoding_rs::mem::detail::null_to_bogus<char16_t>(dst.data()),
162       dst.size());
163 }
164 
165 /**
166  * If the input is valid UTF-16 representing only Unicode code points from
167  * U+0000 to U+00FF, inclusive, converts the input into output that
168  * represents the value of each code point as the unsigned byte value of
169  * each output byte.
170  *
171  * If the input does not fulfill the condition stated above, does something
172  * that is memory-safe without any promises about any properties of the
173  * output and will probably assert in debug builds in future versions.
174  * In particular, callers shouldn't assume the output to be the same across
175  * crate versions or CPU architectures and should not assume that non-ASCII
176  * input can't map to ASCII output.
177  *
178  * The length of the destination buffer must be at least the length of the
179  * source buffer.
180  *
181  * The number of bytes written equals the length of the source buffer.
182  *
183  * # Panics
184  *
185  * Panics if the destination buffer is shorter than stated above.
186  * (Probably in future versions if debug assertions are enabled (and not
187  * fuzzing) and the input is not in the range U+0000 to U+00FF, inclusive.)
188  */
convert_utf16_to_latin1_lossy(std::u16string_view src,gsl::span<char> dst)189 inline void convert_utf16_to_latin1_lossy(std::u16string_view src,
190                                           gsl::span<char> dst) {
191   encoding_mem_convert_utf16_to_latin1_lossy(
192       encoding_rs::mem::detail::null_to_bogus<const char16_t>(src.data()),
193       src.size(), encoding_rs::mem::detail::null_to_bogus<char>(dst.data()),
194       dst.size());
195 }
196 
197 /**
198  * Converts potentially-invalid UTF-16 to valid UTF-8 with errors replaced
199  * with the REPLACEMENT CHARACTER.
200  *
201  * The length of the destination buffer must be at least the length of the
202  * source buffer times three.
203  *
204  * Returns the number of bytes written.
205  *
206  * # Panics
207  *
208  * Panics if the destination buffer is shorter than stated above.
209  */
convert_utf16_to_utf8(std::u16string_view src,gsl::span<char> dst)210 inline size_t convert_utf16_to_utf8(std::u16string_view src,
211                                     gsl::span<char> dst) {
212   return encoding_mem_convert_utf16_to_utf8(
213       encoding_rs::mem::detail::null_to_bogus<const char16_t>(src.data()),
214       src.size(), encoding_rs::mem::detail::null_to_bogus<char>(dst.data()),
215       dst.size());
216 }
217 
218 /**
219  * Converts potentially-invalid UTF-16 to valid UTF-8 with errors replaced
220  * with the REPLACEMENT CHARACTER with potentially insufficient output
221  * space.
222  *
223  * Returns the number of code units read and the number of bytes written.
224  *
225  * Guarantees that the bytes in the destination beyond the number of
226  * bytes claimed as written by the second item of the return tuple
227  * are left unmodified.
228  *
229  * Not all code units are read if there isn't enough output space.
230  * Note  that this method isn't designed for general streamability but for
231  * not allocating memory for the worst case up front. Specifically,
232  * if the input starts with or ends with an unpaired surrogate, those are
233  * replaced with the REPLACEMENT CHARACTER.
234  *
235  * Matches the semantics of `TextEncoder.encodeInto()` from the
236  * Encoding Standard.
237  */
convert_utf16_to_utf8_partial(std::u16string_view src,gsl::span<char> dst)238 inline std::tuple<size_t, size_t> convert_utf16_to_utf8_partial(
239     std::u16string_view src, gsl::span<char> dst) {
240   size_t src_read = src.size();
241   size_t dst_written = dst.size();
242   encoding_mem_convert_utf16_to_utf8_partial(
243       encoding_rs::mem::detail::null_to_bogus<const char16_t>(src.data()),
244       &src_read, encoding_rs::mem::detail::null_to_bogus<char>(dst.data()),
245       &dst_written);
246   return {src_read, dst_written};
247 }
248 
249 /**
250  * If the input is valid UTF-8 representing only Unicode code points from
251  * U+0000 to U+00FF, inclusive, converts the input into output that
252  * represents the value of each code point as the unsigned byte value of
253  * each output byte.
254  *
255  * If the input does not fulfill the condition stated above, this function
256  * panics if debug assertions are enabled (and fuzzing isn't) and otherwise
257  * does something that is memory-safe without any promises about any
258  * properties of the output. In particular, callers shouldn't assume the
259  * output to be the same across crate versions or CPU architectures and
260  * should not assume that non-ASCII input can't map to ASCII output.
261  * The length of the destination buffer must be at least the length of the
262  * source buffer.
263  *
264  * Returns the number of bytes written.
265  *
266  * # Panics
267  *
268  * Panics if the destination buffer is shorter than stated above.
269  * If debug assertions are enabled (and not fuzzing) and the input is
270  * not in the range U+0000 to U+00FF, inclusive.
271  *
272  * # Undefined behavior
273  *
274  * UB ensues if `src` and `dst` overlap.
275  */
convert_utf8_to_latin1_lossy(std::string_view src,gsl::span<char> dst)276 inline size_t convert_utf8_to_latin1_lossy(std::string_view src,
277                                            gsl::span<char> dst) {
278   return encoding_mem_convert_utf8_to_latin1_lossy(
279       encoding_rs::mem::detail::null_to_bogus<const char>(
280           reinterpret_cast<const char*>(src.data())),
281       src.size(), encoding_rs::mem::detail::null_to_bogus<char>(dst.data()),
282       dst.size());
283 }
284 
285 /**
286  * Converts potentially-invalid UTF-8 to valid UTF-16 with errors replaced
287  * with the REPLACEMENT CHARACTER.
288  *
289  * The length of the destination buffer must be at least the length of the
290  * source buffer _plus one_.
291  *
292  * Returns the number of `char16_t`s written.
293  *
294  * # Panics
295  *
296  * Panics if the destination buffer is shorter than stated above.
297  */
convert_utf8_to_utf16(std::string_view src,gsl::span<char16_t> dst)298 inline size_t convert_utf8_to_utf16(std::string_view src,
299                                     gsl::span<char16_t> dst) {
300   return encoding_mem_convert_utf8_to_utf16(
301       encoding_rs::mem::detail::null_to_bogus<const char>(
302           reinterpret_cast<const char*>(src.data())),
303       src.size(), encoding_rs::mem::detail::null_to_bogus<char16_t>(dst.data()),
304       dst.size());
305 }
306 
307 /**
308  * Converts potentially-invalid UTF-8 to valid UTF-16 signaling on error.
309  *
310  * The length of the destination buffer must be at least the length of the
311  * source buffer.
312  *
313  * Returns the number of `char16_t`s written or `std::nullopt` if the input was
314  * invalid.
315  *
316  * When the input was invalid, some output may have been written.
317  *
318  * # Panics
319  *
320  * Panics if the destination buffer is shorter than stated above.
321  */
convert_utf8_to_utf16_without_replacement(std::string_view src,gsl::span<char16_t> dst)322 inline std::optional<size_t> convert_utf8_to_utf16_without_replacement(
323     std::string_view src, gsl::span<char16_t> dst) {
324   size_t val = encoding_mem_convert_utf8_to_utf16_without_replacement(
325       encoding_rs::mem::detail::null_to_bogus<const char>(
326           reinterpret_cast<const char*>(src.data())),
327       src.size(), encoding_rs::mem::detail::null_to_bogus<char16_t>(dst.data()),
328       dst.size());
329   if (val == SIZE_MAX) {
330     return std::nullopt;
331   }
332   return val;
333 }
334 
335 /**
336  * Copies ASCII from source to destination up to the first non-ASCII byte
337  * (or the end of the input if it is ASCII in its entirety).
338  *
339  * The length of the destination buffer must be at least the length of the
340  * source buffer.
341  *
342  * Returns the number of bytes written.
343  *
344  * # Panics
345  *
346  * Panics if the destination buffer is shorter than stated above.
347  *
348  * # Undefined behavior
349  *
350  * UB ensues if `src` and `dst` overlap.
351  */
copy_ascii_to_ascii(gsl::span<const char> src,gsl::span<char> dst)352 inline size_t copy_ascii_to_ascii(gsl::span<const char> src,
353                                   gsl::span<char> dst) {
354   return encoding_mem_copy_ascii_to_ascii(
355       encoding_rs::mem::detail::null_to_bogus<const char>(src.data()),
356       src.size(), encoding_rs::mem::detail::null_to_bogus<char>(dst.data()),
357       dst.size());
358 }
359 
360 /**
361  * Copies ASCII from source to destination zero-extending it to UTF-16 up to
362  * the first non-ASCII byte (or the end of the input if it is ASCII in its
363  * entirety).
364  *
365  * The length of the destination buffer must be at least the length of the
366  * source buffer.
367  *
368  * Returns the number of `char16_t`s written.
369  *
370  * # Panics
371  *
372  * Panics if the destination buffer is shorter than stated above.
373  */
copy_ascii_to_basic_latin(gsl::span<const char> src,gsl::span<char16_t> dst)374 inline size_t copy_ascii_to_basic_latin(gsl::span<const char> src,
375                                         gsl::span<char16_t> dst) {
376   return encoding_mem_copy_ascii_to_basic_latin(
377       encoding_rs::mem::detail::null_to_bogus<const char>(src.data()),
378       src.size(), encoding_rs::mem::detail::null_to_bogus<char16_t>(dst.data()),
379       dst.size());
380 }
381 
382 /**
383  * Copies Basic Latin from source to destination narrowing it to ASCII up to
384  * the first non-Basic Latin code unit (or the end of the input if it is
385  * Basic Latin in its entirety).
386  *
387  * The length of the destination buffer must be at least the length of the
388  * source buffer.
389  *
390  * Returns the number of bytes written.
391  *
392  * # Panics
393  *
394  * Panics if the destination buffer is shorter than stated above.
395  */
copy_basic_latin_to_ascii(gsl::span<const char16_t> src,gsl::span<char> dst)396 inline size_t copy_basic_latin_to_ascii(gsl::span<const char16_t> src,
397                                         gsl::span<char> dst) {
398   return encoding_mem_copy_basic_latin_to_ascii(
399       encoding_rs::mem::detail::null_to_bogus<const char16_t>(src.data()),
400       src.size(), encoding_rs::mem::detail::null_to_bogus<char>(dst.data()),
401       dst.size());
402 }
403 
404 /**
405  * Replaces unpaired surrogates in the input with the REPLACEMENT CHARACTER.
406  */
ensure_utf16_validity(gsl::span<char16_t> buffer)407 inline void ensure_utf16_validity(gsl::span<char16_t> buffer) {
408   encoding_mem_ensure_utf16_validity(
409       encoding_rs::mem::detail::null_to_bogus<char16_t>(buffer.data()),
410       buffer.size());
411 }
412 
413 /**
414  * Checks whether the buffer is all-ASCII.
415  *
416  * May read the entire buffer even if it isn't all-ASCII. (I.e. the function
417  * is not guaranteed to fail fast.)
418  */
is_ascii(std::string_view buffer)419 inline bool is_ascii(std::string_view buffer) {
420   return encoding_mem_is_ascii(
421       encoding_rs::mem::detail::null_to_bogus<const char>(buffer.data()),
422       buffer.size());
423 }
424 
425 /**
426  * Checks whether the buffer is all-Basic Latin (i.e. UTF-16 representing
427  * only ASCII characters).
428  *
429  * May read the entire buffer even if it isn't all-ASCII. (I.e. the function
430  * is not guaranteed to fail fast.)
431  */
is_ascii(std::u16string_view buffer)432 inline bool is_ascii(std::u16string_view buffer) {
433   return encoding_mem_is_basic_latin(
434       encoding_rs::mem::detail::null_to_bogus<const char16_t>(buffer.data()),
435       buffer.size());
436 }
437 
438 /**
439  * Checks whether a scalar value triggers right-to-left processing.
440  *
441  * The check is done on a Unicode block basis without regard to assigned
442  * vs. unassigned code points in the block. Hebrew presentation forms in
443  * the Alphabetic Presentation Forms block are treated as if they formed
444  * a block on their own (i.e. it treated as right-to-left). Additionally,
445  * the four RIGHT-TO-LEFT FOO controls in General Punctuation are checked
446  * for. Control characters that are technically bidi controls but do not
447  * cause right-to-left behavior without the presence of right-to-left
448  * characters or right-to-left controls are not checked for. As a special
449  * case, U+FEFF is excluded from Arabic Presentation Forms-B.
450  *
451  * # Undefined behavior
452  *
453  * Undefined behavior ensues if `c` is not a valid Unicode Scalar Value.
454  */
is_scalar_value_bidi(char32_t c)455 inline bool is_scalar_value_bidi(char32_t c) {
456   return encoding_mem_is_char_bidi(c);
457 }
458 
459 /**
460  * Checks whether a UTF-16 buffer contains code points that trigger
461  * right-to-left processing.
462  *
463  * The check is done on a Unicode block basis without regard to assigned
464  * vs. unassigned code points in the block. Hebrew presentation forms in
465  * the Alphabetic Presentation Forms block are treated as if they formed
466  * a block on their own (i.e. it treated as right-to-left). Additionally,
467  * the four RIGHT-TO-LEFT FOO controls in General Punctuation are checked
468  * for. Control characters that are technically bidi controls but do not
469  * cause right-to-left behavior without the presence of right-to-left
470  * characters or right-to-left controls are not checked for. As a special
471  * case, U+FEFF is excluded from Arabic Presentation Forms-B.
472  * Returns `true` if the input contains an RTL character or an unpaired
473  * high surrogate that could be the high half of an RTL character.
474  * Returns `false` if the input contains neither RTL characters nor
475  * unpaired high surrogates that could be higher halves of RTL characters.
476  */
is_bidi(std::u16string_view buffer)477 inline bool is_bidi(std::u16string_view buffer) {
478   return encoding_mem_is_utf16_bidi(
479       encoding_rs::mem::detail::null_to_bogus<const char16_t>(buffer.data()),
480       buffer.size());
481 }
482 
483 /**
484  * Checks whether a UTF-16 code unit triggers right-to-left processing.
485  *
486  * The check is done on a Unicode block basis without regard to assigned
487  * vs. unassigned code points in the block. Hebrew presentation forms in
488  * the Alphabetic Presentation Forms block are treated as if they formed
489  * a block on their own (i.e. it treated as right-to-left). Additionally,
490  * the four RIGHT-TO-LEFT FOO controls in General Punctuation are checked
491  * for. Control characters that are technically bidi controls but do not
492  * cause right-to-left behavior without the presence of right-to-left
493  * characters or right-to-left controls are not checked for. As a special
494  * case, U+FEFF is excluded from Arabic Presentation Forms-B.
495  * Since supplementary-plane right-to-left blocks are identifiable from the
496  * high surrogate without examining the low surrogate, this function returns
497  * `true` for such high surrogates making the function suitable for handling
498  * supplementary-plane text without decoding surrogate pairs to scalar
499  * values. Obviously, such high surrogates are then reported as right-to-left
500  * even if actually unpaired.
501  */
is_utf16_code_unit_bidi(char16_t u)502 inline bool is_utf16_code_unit_bidi(char16_t u) {
503   return encoding_mem_is_utf16_code_unit_bidi(u);
504 }
505 
506 /**
507  * Checks whether the buffer represents only code point less than or equal
508  * to U+00FF.
509  *
510  * May read the entire buffer even if it isn't all-Latin1. (I.e. the function
511  * is not guaranteed to fail fast.)
512  */
is_utf16_latin1(std::u16string_view buffer)513 inline bool is_utf16_latin1(std::u16string_view buffer) {
514   return encoding_mem_is_utf16_latin1(
515       encoding_rs::mem::detail::null_to_bogus<const char16_t>(buffer.data()),
516       buffer.size());
517 }
518 
519 /**
520  * Checks whether a potentially-invalid UTF-8 buffer contains code points
521  * that trigger right-to-left processing.
522  *
523  * The check is done on a Unicode block basis without regard to assigned
524  * vs. unassigned code points in the block. Hebrew presentation forms in
525  * the Alphabetic Presentation Forms block are treated as if they formed
526  * a block on their own (i.e. it treated as right-to-left). Additionally,
527  * the four RIGHT-TO-LEFT FOO controls in General Punctuation are checked
528  * for. Control characters that are technically bidi controls but do not
529  * cause right-to-left behavior without the presence of right-to-left
530  * characters or right-to-left controls are not checked for. As a special
531  * case, U+FEFF is excluded from Arabic Presentation Forms-B.
532  * Returns `true` if the input is invalid UTF-8 or the input contains an
533  * RTL character. Returns `false` if the input is valid UTF-8 and contains
534  * no RTL characters.
535  */
is_bidi(std::string_view buffer)536 inline bool is_bidi(std::string_view buffer) {
537   return encoding_mem_is_utf8_bidi(
538       encoding_rs::mem::detail::null_to_bogus<const char>(buffer.data()),
539       buffer.size());
540 }
541 
542 /**
543  * Checks whether the buffer is valid UTF-8 representing only code points
544  * less than or equal to U+00FF.
545  *
546  * Fails fast. (I.e. returns before having read the whole buffer if UTF-8
547  * invalidity or code points above U+00FF are discovered.
548  */
is_utf8_latin1(std::string_view buffer)549 inline bool is_utf8_latin1(std::string_view buffer) {
550   return encoding_mem_is_utf8_latin1(
551       encoding_rs::mem::detail::null_to_bogus<const char>(buffer.data()),
552       buffer.size());
553 }
554 
555 /**
556  * Returns the index of the first unpaired surrogate or, if the input is
557  * valid UTF-16 in its entirety, the length of the input.
558  */
utf16_valid_up_to(std::u16string_view buffer)559 inline size_t utf16_valid_up_to(std::u16string_view buffer) {
560   return encoding_mem_utf16_valid_up_to(
561       encoding_rs::mem::detail::null_to_bogus<const char16_t>(buffer.data()),
562       buffer.size());
563 }
564 
565 /**
566  * Returns the index of first byte that starts a non-Latin1 byte
567  * sequence, or the length of the string if there are none.
568  */
utf8_latin1_up_to(std::string_view buffer)569 inline size_t utf8_latin1_up_to(std::string_view buffer) {
570   return encoding_mem_utf8_latin1_up_to(
571       encoding_rs::mem::detail::null_to_bogus<const char>(buffer.data()),
572       buffer.size());
573 }
574 
575 };  // namespace mem
576 };  // namespace encoding_rs
577 
578 #endif  // encoding_rs_mem_cpp_h_
579