encoding_c/
lib.rs

1// Copyright 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#![doc(html_root_url = "https://docs.rs/encoding_c/0.9.7")]
11
12//! The C API for encoding_rs.
13//!
14//! # Mapping from Rust
15//!
16//! ## Naming convention
17//!
18//! The wrapper function for each method has a name that starts with the name
19//! of the struct lower-cased, followed by an underscore and ends with the
20//! name of the method.
21//!
22//! For example, `Encoding::for_label()` is wrapped as `encoding_for_label()`.
23//!
24//! ## Arguments
25//!
26//! Functions that wrap non-static methods take the `self` object as their
27//! first argument.
28//!
29//! Slice argument `foo` is decomposed into a pointer `foo` and a length
30//! `foo_len`.
31//!
32//! ## Return values
33//!
34//! Multiple return values become out-params. When an out-param is
35//! length-related, `foo_len` for a slice becomes a pointer in order to become
36//! an in/out-param.
37//!
38//! `DecoderResult`, `EncoderResult` and `CoderResult` become `uint32_t`.
39//! `InputEmpty` becomes `INPUT_EMPTY`. `OutputFull` becomes `OUTPUT_FULL`.
40//! `Unmappable` becomes the scalar value of the unmappable character.
41//! `Malformed` becomes a number whose lowest 8 bits, which can have the decimal
42//! value 0, 1, 2 or 3, indicate the number of bytes that were consumed after
43//! the malformed sequence and whose next-lowest 8 bits, when shifted right by
44//! 8 indicate the length of the malformed byte sequence (possible decimal
45//! values 1, 2, 3 or 4). The maximum possible sum of the two is 6.
46
47extern crate encoding_rs;
48
49use encoding_rs::*;
50
51/// Return value for `*_decode_*` and `*_encode_*` functions that indicates that
52/// the input has been exhausted.
53///
54/// (This is zero as a micro optimization. U+0000 is never unmappable and
55/// malformed sequences always have a positive length.)
56pub const INPUT_EMPTY: u32 = 0;
57
58/// Return value for `*_decode_*` and `*_encode_*` functions that indicates that
59/// the output space has been exhausted.
60pub const OUTPUT_FULL: u32 = 0xFFFFFFFF;
61
62/// Newtype for `*const Encoding` in order to be able to implement `Sync` for
63/// it.
64pub struct ConstEncoding(*const Encoding);
65
66/// Required for `static` fields.
67unsafe impl Sync for ConstEncoding {}
68
69// BEGIN GENERATED CODE. PLEASE DO NOT EDIT.
70// Instead, please regenerate using generate-encoding-data.py
71
72/// The minimum length of buffers that may be passed to `encoding_name()`.
73pub const ENCODING_NAME_MAX_LENGTH: usize = 14; // x-mac-cyrillic
74
75/// The Big5 encoding.
76#[no_mangle]
77pub static BIG5_ENCODING: ConstEncoding = ConstEncoding(&BIG5_INIT);
78
79/// The EUC-JP encoding.
80#[no_mangle]
81pub static EUC_JP_ENCODING: ConstEncoding = ConstEncoding(&EUC_JP_INIT);
82
83/// The EUC-KR encoding.
84#[no_mangle]
85pub static EUC_KR_ENCODING: ConstEncoding = ConstEncoding(&EUC_KR_INIT);
86
87/// The GBK encoding.
88#[no_mangle]
89pub static GBK_ENCODING: ConstEncoding = ConstEncoding(&GBK_INIT);
90
91/// The IBM866 encoding.
92#[no_mangle]
93pub static IBM866_ENCODING: ConstEncoding = ConstEncoding(&IBM866_INIT);
94
95/// The ISO-2022-JP encoding.
96#[no_mangle]
97pub static ISO_2022_JP_ENCODING: ConstEncoding = ConstEncoding(&ISO_2022_JP_INIT);
98
99/// The ISO-8859-10 encoding.
100#[no_mangle]
101pub static ISO_8859_10_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_10_INIT);
102
103/// The ISO-8859-13 encoding.
104#[no_mangle]
105pub static ISO_8859_13_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_13_INIT);
106
107/// The ISO-8859-14 encoding.
108#[no_mangle]
109pub static ISO_8859_14_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_14_INIT);
110
111/// The ISO-8859-15 encoding.
112#[no_mangle]
113pub static ISO_8859_15_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_15_INIT);
114
115/// The ISO-8859-16 encoding.
116#[no_mangle]
117pub static ISO_8859_16_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_16_INIT);
118
119/// The ISO-8859-2 encoding.
120#[no_mangle]
121pub static ISO_8859_2_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_2_INIT);
122
123/// The ISO-8859-3 encoding.
124#[no_mangle]
125pub static ISO_8859_3_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_3_INIT);
126
127/// The ISO-8859-4 encoding.
128#[no_mangle]
129pub static ISO_8859_4_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_4_INIT);
130
131/// The ISO-8859-5 encoding.
132#[no_mangle]
133pub static ISO_8859_5_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_5_INIT);
134
135/// The ISO-8859-6 encoding.
136#[no_mangle]
137pub static ISO_8859_6_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_6_INIT);
138
139/// The ISO-8859-7 encoding.
140#[no_mangle]
141pub static ISO_8859_7_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_7_INIT);
142
143/// The ISO-8859-8 encoding.
144#[no_mangle]
145pub static ISO_8859_8_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_8_INIT);
146
147/// The ISO-8859-8-I encoding.
148#[no_mangle]
149pub static ISO_8859_8_I_ENCODING: ConstEncoding = ConstEncoding(&ISO_8859_8_I_INIT);
150
151/// The KOI8-R encoding.
152#[no_mangle]
153pub static KOI8_R_ENCODING: ConstEncoding = ConstEncoding(&KOI8_R_INIT);
154
155/// The KOI8-U encoding.
156#[no_mangle]
157pub static KOI8_U_ENCODING: ConstEncoding = ConstEncoding(&KOI8_U_INIT);
158
159/// The Shift_JIS encoding.
160#[no_mangle]
161pub static SHIFT_JIS_ENCODING: ConstEncoding = ConstEncoding(&SHIFT_JIS_INIT);
162
163/// The UTF-16BE encoding.
164#[no_mangle]
165pub static UTF_16BE_ENCODING: ConstEncoding = ConstEncoding(&UTF_16BE_INIT);
166
167/// The UTF-16LE encoding.
168#[no_mangle]
169pub static UTF_16LE_ENCODING: ConstEncoding = ConstEncoding(&UTF_16LE_INIT);
170
171/// The UTF-8 encoding.
172#[no_mangle]
173pub static UTF_8_ENCODING: ConstEncoding = ConstEncoding(&UTF_8_INIT);
174
175/// The gb18030 encoding.
176#[no_mangle]
177pub static GB18030_ENCODING: ConstEncoding = ConstEncoding(&GB18030_INIT);
178
179/// The macintosh encoding.
180#[no_mangle]
181pub static MACINTOSH_ENCODING: ConstEncoding = ConstEncoding(&MACINTOSH_INIT);
182
183/// The replacement encoding.
184#[no_mangle]
185pub static REPLACEMENT_ENCODING: ConstEncoding = ConstEncoding(&REPLACEMENT_INIT);
186
187/// The windows-1250 encoding.
188#[no_mangle]
189pub static WINDOWS_1250_ENCODING: ConstEncoding = ConstEncoding(&WINDOWS_1250_INIT);
190
191/// The windows-1251 encoding.
192#[no_mangle]
193pub static WINDOWS_1251_ENCODING: ConstEncoding = ConstEncoding(&WINDOWS_1251_INIT);
194
195/// The windows-1252 encoding.
196#[no_mangle]
197pub static WINDOWS_1252_ENCODING: ConstEncoding = ConstEncoding(&WINDOWS_1252_INIT);
198
199/// The windows-1253 encoding.
200#[no_mangle]
201pub static WINDOWS_1253_ENCODING: ConstEncoding = ConstEncoding(&WINDOWS_1253_INIT);
202
203/// The windows-1254 encoding.
204#[no_mangle]
205pub static WINDOWS_1254_ENCODING: ConstEncoding = ConstEncoding(&WINDOWS_1254_INIT);
206
207/// The windows-1255 encoding.
208#[no_mangle]
209pub static WINDOWS_1255_ENCODING: ConstEncoding = ConstEncoding(&WINDOWS_1255_INIT);
210
211/// The windows-1256 encoding.
212#[no_mangle]
213pub static WINDOWS_1256_ENCODING: ConstEncoding = ConstEncoding(&WINDOWS_1256_INIT);
214
215/// The windows-1257 encoding.
216#[no_mangle]
217pub static WINDOWS_1257_ENCODING: ConstEncoding = ConstEncoding(&WINDOWS_1257_INIT);
218
219/// The windows-1258 encoding.
220#[no_mangle]
221pub static WINDOWS_1258_ENCODING: ConstEncoding = ConstEncoding(&WINDOWS_1258_INIT);
222
223/// The windows-874 encoding.
224#[no_mangle]
225pub static WINDOWS_874_ENCODING: ConstEncoding = ConstEncoding(&WINDOWS_874_INIT);
226
227/// The x-mac-cyrillic encoding.
228#[no_mangle]
229pub static X_MAC_CYRILLIC_ENCODING: ConstEncoding = ConstEncoding(&X_MAC_CYRILLIC_INIT);
230
231/// The x-user-defined encoding.
232#[no_mangle]
233pub static X_USER_DEFINED_ENCODING: ConstEncoding = ConstEncoding(&X_USER_DEFINED_INIT);
234
235// END GENERATED CODE
236
237#[inline(always)]
238fn coder_result_to_u32(result: CoderResult) -> u32 {
239    match result {
240        CoderResult::InputEmpty => INPUT_EMPTY,
241        CoderResult::OutputFull => OUTPUT_FULL,
242    }
243}
244
245#[inline(always)]
246fn decoder_result_to_u32(result: DecoderResult) -> u32 {
247    match result {
248        DecoderResult::InputEmpty => INPUT_EMPTY,
249        DecoderResult::OutputFull => OUTPUT_FULL,
250        DecoderResult::Malformed(bad, good) => ((good as u32) << 8) | (bad as u32),
251    }
252}
253
254#[inline(always)]
255fn encoder_result_to_u32(result: EncoderResult) -> u32 {
256    match result {
257        EncoderResult::InputEmpty => INPUT_EMPTY,
258        EncoderResult::OutputFull => OUTPUT_FULL,
259        EncoderResult::Unmappable(c) => c as u32,
260    }
261}
262
263#[inline(always)]
264fn option_to_ptr(opt: Option<&'static Encoding>) -> *const Encoding {
265    match opt {
266        None => ::std::ptr::null(),
267        Some(e) => e,
268    }
269}
270
271/// Implements the
272/// [_get an encoding_](https://encoding.spec.whatwg.org/#concept-encoding-get)
273/// algorithm.
274///
275/// If, after ASCII-lowercasing and removing leading and trailing
276/// whitespace, the argument matches a label defined in the Encoding
277/// Standard, `const Encoding*` representing the corresponding
278/// encoding is returned. If there is no match, `NULL` is returned.
279///
280/// This is the right function to use if the action upon the method returning
281/// `NULL` is to use a fallback encoding (e.g. `WINDOWS_1252_ENCODING`) instead.
282/// When the action upon the method returning `NULL` is not to proceed with
283/// a fallback but to refuse processing, `encoding_for_label_no_replacement()` is
284/// more appropriate.
285///
286/// The argument buffer can be in any ASCII-compatible encoding. It is not
287/// required to be UTF-8.
288///
289/// `label` must be non-`NULL` even if `label_len` is zero. When `label_len`
290/// is zero, it is OK for `label` to be something non-dereferencable,
291/// such as `0x1`. This is required due to Rust's optimization for slices
292/// within `Option`.
293///
294/// # Undefined behavior
295///
296/// UB ensues if `label` and `label_len` don't designate a valid memory block
297/// of if `label` is `NULL`.
298#[no_mangle]
299pub unsafe extern "C" fn encoding_for_label(label: *const u8, label_len: usize) -> *const Encoding {
300    let label_slice = ::std::slice::from_raw_parts(label, label_len);
301    option_to_ptr(Encoding::for_label(label_slice))
302}
303
304/// This function behaves the same as `encoding_for_label()`, except when
305/// `encoding_for_label()` would return `REPLACEMENT_ENCODING`, this method
306/// returns `NULL` instead.
307///
308/// This method is useful in scenarios where a fatal error is required
309/// upon invalid label, because in those cases the caller typically wishes
310/// to treat the labels that map to the replacement encoding as fatal
311/// errors, too.
312///
313/// It is not OK to use this funciton when the action upon the method returning
314/// `NULL` is to use a fallback encoding (e.g. `WINDOWS_1252_ENCODING`). In
315/// such a case, the `encoding_for_label()` function should be used instead
316/// in order to avoid unsafe fallback for labels that `encoding_for_label()`
317/// maps to `REPLACEMENT_ENCODING`.
318///
319/// The argument buffer can be in any ASCII-compatible encoding. It is not
320/// required to be UTF-8.
321///
322/// `label` must be non-`NULL` even if `label_len` is zero. When `label_len`
323/// is zero, it is OK for `label` to be something non-dereferencable,
324/// such as `0x1`. This is required due to Rust's optimization for slices
325/// within `Option`.
326///
327/// # Undefined behavior
328///
329/// UB ensues if `label` and `label_len` don't designate a valid memory block
330/// of if `label` is `NULL`.
331#[no_mangle]
332pub unsafe extern "C" fn encoding_for_label_no_replacement(
333    label: *const u8,
334    label_len: usize,
335) -> *const Encoding {
336    let label_slice = ::std::slice::from_raw_parts(label, label_len);
337    option_to_ptr(Encoding::for_label_no_replacement(label_slice))
338}
339
340/// Performs non-incremental BOM sniffing.
341///
342/// The argument must either be a buffer representing the entire input
343/// stream (non-streaming case) or a buffer representing at least the first
344/// three bytes of the input stream (streaming case).
345///
346/// Returns `UTF_8_ENCODING`, `UTF_16LE_ENCODING` or `UTF_16BE_ENCODING` if the
347/// argument starts with the UTF-8, UTF-16LE or UTF-16BE BOM or `NULL`
348/// otherwise. Upon return, `*buffer_len` is the length of the BOM (zero if
349/// there is no BOM).
350///
351/// `buffer` must be non-`NULL` even if `*buffer_len` is zero. When
352/// `*buffer_len` is zero, it is OK for `buffer` to be something
353/// non-dereferencable, such as `0x1`. This is required due to Rust's
354/// optimization for slices within `Option`.
355///
356/// # Undefined behavior
357///
358/// UB ensues if `buffer` and `*buffer_len` don't designate a valid memory
359/// block of if `buffer` is `NULL`.
360#[no_mangle]
361pub unsafe extern "C" fn encoding_for_bom(
362    buffer: *const u8,
363    buffer_len: *mut usize,
364) -> *const Encoding {
365    let buffer_slice = ::std::slice::from_raw_parts(buffer, *buffer_len);
366    let (encoding, bom_length) = match Encoding::for_bom(buffer_slice) {
367        Some((encoding, bom_length)) => (encoding as *const Encoding, bom_length),
368        None => (::std::ptr::null(), 0),
369    };
370    *buffer_len = bom_length;
371    encoding
372}
373
374/// Writes the name of the given `Encoding` to a caller-supplied buffer as
375/// ASCII and returns the number of bytes / ASCII characters written.
376///
377/// The output is not null-terminated.
378///
379/// The caller _MUST_ ensure that `name_out` points to a buffer whose length
380/// is at least `ENCODING_NAME_MAX_LENGTH` bytes.
381///
382/// # Undefined behavior
383///
384/// UB ensues if either argument is `NULL` or if `name_out` doesn't point to
385/// a valid block of memory whose length is at least
386/// `ENCODING_NAME_MAX_LENGTH` bytes.
387#[no_mangle]
388pub unsafe extern "C" fn encoding_name(encoding: *const Encoding, name_out: *mut u8) -> usize {
389    let bytes = (*encoding).name().as_bytes();
390    ::std::ptr::copy_nonoverlapping(bytes.as_ptr(), name_out, bytes.len());
391    bytes.len()
392}
393
394/// Checks whether the _output encoding_ of this encoding can encode every
395/// Unicode scalar. (Only true if the output encoding is UTF-8.)
396///
397/// # Undefined behavior
398///
399/// UB ensues if the argument is `NULL`.
400#[no_mangle]
401pub unsafe extern "C" fn encoding_can_encode_everything(encoding: *const Encoding) -> bool {
402    (*encoding).can_encode_everything()
403}
404
405/// Checks whether the bytes 0x00...0x7F map exclusively to the characters
406/// U+0000...U+007F and vice versa.
407///
408/// # Undefined behavior
409///
410/// UB ensues if the argument is `NULL`.
411#[no_mangle]
412pub unsafe extern "C" fn encoding_is_ascii_compatible(encoding: *const Encoding) -> bool {
413    (*encoding).is_ascii_compatible()
414}
415
416/// Checks whether this encoding maps one byte to one Basic Multilingual
417/// Plane code point (i.e. byte length equals decoded UTF-16 length) and
418/// vice versa (for mappable characters).
419///
420/// `true` iff this encoding is on the list of [Legacy single-byte
421/// encodings](https://encoding.spec.whatwg.org/#legacy-single-byte-encodings)
422/// in the spec or x-user-defined.
423///
424/// # Undefined behavior
425///
426/// UB ensues if the argument is `NULL`.
427#[no_mangle]
428pub unsafe extern "C" fn encoding_is_single_byte(encoding: *const Encoding) -> bool {
429    (*encoding).is_single_byte()
430}
431
432/// Returns the _output encoding_ of this encoding. This is UTF-8 for
433/// UTF-16BE, UTF-16LE and replacement and the encoding itself otherwise.
434///
435/// # Undefined behavior
436///
437/// UB ensues if the argument is `NULL`.
438#[no_mangle]
439pub unsafe extern "C" fn encoding_output_encoding(encoding: *const Encoding) -> *const Encoding {
440    (*encoding).output_encoding()
441}
442
443/// Allocates a new `Decoder` for the given `Encoding` on the heap with BOM
444/// sniffing enabled and returns a pointer to the newly-allocated `Decoder`.
445///
446/// BOM sniffing may cause the returned decoder to morph into a decoder
447/// for UTF-8, UTF-16LE or UTF-16BE instead of this encoding.
448///
449/// Once the allocated `Decoder` is no longer needed, the caller _MUST_
450/// deallocate it by passing the pointer returned by this function to
451/// `decoder_free()`.
452///
453/// # Undefined behavior
454///
455/// UB ensues if the argument is `NULL`.
456#[no_mangle]
457pub unsafe extern "C" fn encoding_new_decoder(encoding: *const Encoding) -> *mut Decoder {
458    Box::into_raw(Box::new((*encoding).new_decoder()))
459}
460
461/// Allocates a new `Decoder` for the given `Encoding` on the heap with BOM
462/// removal and returns a pointer to the newly-allocated `Decoder`.
463///
464/// If the input starts with bytes that are the BOM for this encoding,
465/// those bytes are removed. However, the decoder never morphs into a
466/// decoder for another encoding: A BOM for another encoding is treated as
467/// (potentially malformed) input to the decoding algorithm for this
468/// encoding.
469///
470/// Once the allocated `Decoder` is no longer needed, the caller _MUST_
471/// deallocate it by passing the pointer returned by this function to
472/// `decoder_free()`.
473///
474/// # Undefined behavior
475///
476/// UB ensues if the argument is `NULL`.
477#[no_mangle]
478pub unsafe extern "C" fn encoding_new_decoder_with_bom_removal(
479    encoding: *const Encoding,
480) -> *mut Decoder {
481    Box::into_raw(Box::new((*encoding).new_decoder_with_bom_removal()))
482}
483
484/// Allocates a new `Decoder` for the given `Encoding` on the heap with BOM
485/// handling disabled and returns a pointer to the newly-allocated `Decoder`.
486///
487/// If the input starts with bytes that look like a BOM, those bytes are
488/// not treated as a BOM. (Hence, the decoder never morphs into a decoder
489/// for another encoding.)
490///
491/// _Note:_ If the caller has performed BOM sniffing on its own but has not
492/// removed the BOM, the caller should use
493/// `encoding_new_decoder_with_bom_removal()` instead of this function to cause
494/// the BOM to be removed.
495///
496/// Once the allocated `Decoder` is no longer needed, the caller _MUST_
497/// deallocate it by passing the pointer returned by this function to
498/// `decoder_free()`.
499///
500/// # Undefined behavior
501///
502/// UB ensues if the argument is `NULL`.
503#[no_mangle]
504pub unsafe extern "C" fn encoding_new_decoder_without_bom_handling(
505    encoding: *const Encoding,
506) -> *mut Decoder {
507    Box::into_raw(Box::new((*encoding).new_decoder_without_bom_handling()))
508}
509
510/// Allocates a new `Decoder` for the given `Encoding` into memory provided by
511/// the caller with BOM sniffing enabled. (In practice, the target should
512/// likely be a pointer previously returned by `encoding_new_decoder()`.)
513///
514/// Note: If the caller has already performed BOM sniffing but has
515/// not removed the BOM, the caller should still use this function in
516/// order to cause the BOM to be ignored.
517///
518/// # Undefined behavior
519///
520/// UB ensues if either argument is `NULL`.
521#[no_mangle]
522pub unsafe extern "C" fn encoding_new_decoder_into(
523    encoding: *const Encoding,
524    decoder: *mut Decoder,
525) {
526    *decoder = (*encoding).new_decoder();
527}
528
529/// Allocates a new `Decoder` for the given `Encoding` into memory provided by
530/// the caller with BOM removal.
531///
532/// If the input starts with bytes that are the BOM for this encoding,
533/// those bytes are removed. However, the decoder never morphs into a
534/// decoder for another encoding: A BOM for another encoding is treated as
535/// (potentially malformed) input to the decoding algorithm for this
536/// encoding.
537///
538/// Once the allocated `Decoder` is no longer needed, the caller _MUST_
539/// deallocate it by passing the pointer returned by this function to
540/// `decoder_free()`.
541///
542/// # Undefined behavior
543///
544/// UB ensues if either argument is `NULL`.
545#[no_mangle]
546pub unsafe extern "C" fn encoding_new_decoder_with_bom_removal_into(
547    encoding: *const Encoding,
548    decoder: *mut Decoder,
549) {
550    *decoder = (*encoding).new_decoder_with_bom_removal();
551}
552
553/// Allocates a new `Decoder` for the given `Encoding` into memory provided by
554/// the caller with BOM handling disabled.
555///
556/// If the input starts with bytes that look like a BOM, those bytes are
557/// not treated as a BOM. (Hence, the decoder never morphs into a decoder
558/// for another encoding.)
559///
560/// _Note:_ If the caller has performed BOM sniffing on its own but has not
561/// removed the BOM, the caller should use
562/// `encoding_new_decoder_with_bom_removal_into()` instead of this function to
563/// cause the BOM to be removed.
564///
565/// # Undefined behavior
566///
567/// UB ensues if either argument is `NULL`.
568#[no_mangle]
569pub unsafe extern "C" fn encoding_new_decoder_without_bom_handling_into(
570    encoding: *const Encoding,
571    decoder: *mut Decoder,
572) {
573    *decoder = (*encoding).new_decoder_without_bom_handling();
574}
575
576/// Allocates a new `Encoder` for the given `Encoding` on the heap and returns a
577/// pointer to the newly-allocated `Encoder`. (Exception, if the `Encoding` is
578/// `replacement`, a new `Decoder` for UTF-8 is instantiated (and that
579/// `Decoder` reports `UTF_8` as its `Encoding`).
580///
581/// Once the allocated `Encoder` is no longer needed, the caller _MUST_
582/// deallocate it by passing the pointer returned by this function to
583/// `encoder_free()`.
584///
585/// # Undefined behavior
586///
587/// UB ensues if the argument is `NULL`.
588#[no_mangle]
589pub unsafe extern "C" fn encoding_new_encoder(encoding: *const Encoding) -> *mut Encoder {
590    Box::into_raw(Box::new((*encoding).new_encoder()))
591}
592
593/// Allocates a new `Encoder` for the given `Encoding` into memory provided by
594/// the caller. (In practice, the target should likely be a pointer previously
595/// returned by `encoding_new_encoder()`.)
596///
597/// # Undefined behavior
598///
599/// UB ensues if either argument is `NULL`.
600#[no_mangle]
601pub unsafe extern "C" fn encoding_new_encoder_into(
602    encoding: *const Encoding,
603    encoder: *mut Encoder,
604) {
605    *encoder = (*encoding).new_encoder();
606}
607
608/// Validates UTF-8.
609///
610/// Returns the index of the first byte that makes the input malformed as
611/// UTF-8 or `buffer_len` if `buffer` is entirely valid.
612///
613/// `buffer` must be non-`NULL` even if `buffer_len` is zero. When
614/// `buffer_len` is zero, it is OK for `buffer` to be something
615/// non-dereferencable, such as `0x1`. This is required due to Rust's
616/// optimization for slices within `Option`.
617///
618/// # Undefined behavior
619///
620/// UB ensues if `buffer` and `buffer_len` don't designate a valid memory
621/// block of if `buffer` is `NULL`.
622#[no_mangle]
623pub unsafe extern "C" fn encoding_utf8_valid_up_to(buffer: *const u8, buffer_len: usize) -> usize {
624    let buffer_slice = ::std::slice::from_raw_parts(buffer, buffer_len);
625    Encoding::utf8_valid_up_to(buffer_slice)
626}
627
628/// Validates ASCII.
629///
630/// Returns the index of the first byte that makes the input malformed as
631/// ASCII or `buffer_len` if `buffer` is entirely valid.
632///
633/// `buffer` must be non-`NULL` even if `buffer_len` is zero. When
634/// `buffer_len` is zero, it is OK for `buffer` to be something
635/// non-dereferencable, such as `0x1`. This is required due to Rust's
636/// optimization for slices within `Option`.
637///
638/// # Undefined behavior
639///
640/// UB ensues if `buffer` and `buffer_len` don't designate a valid memory
641/// block of if `buffer` is `NULL`.
642#[no_mangle]
643pub unsafe extern "C" fn encoding_ascii_valid_up_to(buffer: *const u8, buffer_len: usize) -> usize {
644    let buffer_slice = ::std::slice::from_raw_parts(buffer, buffer_len);
645    Encoding::ascii_valid_up_to(buffer_slice)
646}
647
648/// Validates ISO-2022-JP ASCII-state data.
649///
650/// Returns the index of the first byte that makes the input not representable
651/// in the ASCII state of ISO-2022-JP or `buffer_len` if `buffer` is entirely
652/// representable in the ASCII state of ISO-2022-JP.
653///
654/// `buffer` must be non-`NULL` even if `buffer_len` is zero. When
655/// `buffer_len` is zero, it is OK for `buffer` to be something
656/// non-dereferencable, such as `0x1`. This is required due to Rust's
657/// optimization for slices within `Option`.
658///
659/// # Undefined behavior
660///
661/// UB ensues if `buffer` and `buffer_len` don't designate a valid memory
662/// block of if `buffer` is `NULL`.
663#[no_mangle]
664pub unsafe extern "C" fn encoding_iso_2022_jp_ascii_valid_up_to(
665    buffer: *const u8,
666    buffer_len: usize,
667) -> usize {
668    let buffer_slice = ::std::slice::from_raw_parts(buffer, buffer_len);
669    Encoding::iso_2022_jp_ascii_valid_up_to(buffer_slice)
670}
671
672/// Deallocates a `Decoder` previously allocated by `encoding_new_decoder()`.
673///
674/// # Undefined behavior
675///
676/// UB ensues if the argument is `NULL`.
677#[no_mangle]
678pub unsafe extern "C" fn decoder_free(decoder: *mut Decoder) {
679    let _ = Box::from_raw(decoder);
680}
681
682/// The `Encoding` this `Decoder` is for.
683///
684/// BOM sniffing can change the return value of this method during the life
685/// of the decoder.
686///
687/// # Undefined behavior
688///
689/// UB ensues if the argument is `NULL`.
690#[no_mangle]
691pub unsafe extern "C" fn decoder_encoding(decoder: *const Decoder) -> *const Encoding {
692    (*decoder).encoding()
693}
694
695/// Query the worst-case UTF-8 output size _with replacement_.
696///
697/// Returns the size of the output buffer in UTF-8 code units (`uint8_t`)
698/// that will not overflow given the current state of the decoder and
699/// `byte_length` number of additional input bytes when decoding with
700/// errors handled by outputting a REPLACEMENT CHARACTER for each malformed
701/// sequence or `SIZE_MAX` if `size_t` would overflow.
702///
703/// # Undefined behavior
704///
705/// UB ensues if `decoder` is `NULL`.
706#[no_mangle]
707pub unsafe extern "C" fn decoder_max_utf8_buffer_length(
708    decoder: *const Decoder,
709    byte_length: usize,
710) -> usize {
711    (*decoder)
712        .max_utf8_buffer_length(byte_length)
713        .unwrap_or(::std::usize::MAX)
714}
715
716/// Query the worst-case UTF-8 output size _without replacement_.
717///
718/// Returns the size of the output buffer in UTF-8 code units (`uint8_t`)
719/// that will not overflow given the current state of the decoder and
720/// `byte_length` number of additional input bytes when decoding without
721/// replacement error handling or `SIZE_MAX` if `size_t` would overflow.
722///
723/// Note that this value may be too small for the `_with_replacement` case.
724/// Use `decoder_max_utf8_buffer_length()` for that case.
725///
726/// # Undefined behavior
727///
728/// UB ensues if `decoder` is `NULL`.
729#[no_mangle]
730pub unsafe extern "C" fn decoder_max_utf8_buffer_length_without_replacement(
731    decoder: *const Decoder,
732    byte_length: usize,
733) -> usize {
734    (*decoder)
735        .max_utf8_buffer_length_without_replacement(byte_length)
736        .unwrap_or(::std::usize::MAX)
737}
738
739/// Incrementally decode a byte stream into UTF-8 with malformed sequences
740/// replaced with the REPLACEMENT CHARACTER.
741///
742/// See the top-level FFI documentation for documentation for how the
743/// `decoder_decode_*` functions are mapped from Rust and the documentation
744/// for the [`Decoder`][1] struct for the semantics.
745///
746/// `src` must be non-`NULL` even if `src_len` is zero. When`src_len` is zero,
747/// it is OK for `src` to be something non-dereferencable, such as `0x1`.
748/// Likewise for `dst` when `dst_len` is zero. This is required due to Rust's
749/// optimization for slices within `Option`.
750///
751/// # Undefined behavior
752///
753/// UB ensues if any of the pointer arguments is `NULL`, `src` and `src_len`
754/// don't designate a valid block of memory or `dst` and `dst_len` don't
755/// designate a valid block of memory.
756///
757/// [1]: https://docs.rs/encoding_rs/0.6.10/encoding_rs/struct.Decoder.html
758#[no_mangle]
759pub unsafe extern "C" fn decoder_decode_to_utf8(
760    decoder: *mut Decoder,
761    src: *const u8,
762    src_len: *mut usize,
763    dst: *mut u8,
764    dst_len: *mut usize,
765    last: bool,
766    had_replacements: *mut bool,
767) -> u32 {
768    let src_slice = ::std::slice::from_raw_parts(src, *src_len);
769    let dst_slice = ::std::slice::from_raw_parts_mut(dst, *dst_len);
770    let (result, read, written, replaced) = (*decoder).decode_to_utf8(src_slice, dst_slice, last);
771    *src_len = read;
772    *dst_len = written;
773    *had_replacements = replaced;
774    coder_result_to_u32(result)
775}
776
777/// Incrementally decode a byte stream into UTF-8 _without replacement_.
778///
779/// See the top-level FFI documentation for documentation for how the
780/// `decoder_decode_*` functions are mapped from Rust and the documentation
781/// for the [`Decoder`][1] struct for the semantics.
782///
783/// `src` must be non-`NULL` even if `src_len` is zero. When`src_len` is zero,
784/// it is OK for `src` to be something non-dereferencable, such as `0x1`.
785/// Likewise for `dst` when `dst_len` is zero. This is required due to Rust's
786/// optimization for slices within `Option`.
787///
788/// # Undefined behavior
789///
790/// UB ensues if any of the pointer arguments is `NULL`, `src` and `src_len`
791/// don't designate a valid block of memory or `dst` and `dst_len` don't
792/// designate a valid block of memory.
793///
794/// [1]: https://docs.rs/encoding_rs/0.6.10/encoding_rs/struct.Decoder.html
795#[no_mangle]
796pub unsafe extern "C" fn decoder_decode_to_utf8_without_replacement(
797    decoder: *mut Decoder,
798    src: *const u8,
799    src_len: *mut usize,
800    dst: *mut u8,
801    dst_len: *mut usize,
802    last: bool,
803) -> u32 {
804    let src_slice = ::std::slice::from_raw_parts(src, *src_len);
805    let dst_slice = ::std::slice::from_raw_parts_mut(dst, *dst_len);
806    let (result, read, written) =
807        (*decoder).decode_to_utf8_without_replacement(src_slice, dst_slice, last);
808    *src_len = read;
809    *dst_len = written;
810    decoder_result_to_u32(result)
811}
812
813/// Query the worst-case UTF-16 output size (with or without replacement).
814///
815/// Returns the size of the output buffer in UTF-16 code units (`char16_t`)
816/// that will not overflow given the current state of the decoder and
817/// `byte_length` number of additional input bytes or `SIZE_MAX` if `size_t`
818/// would overflow.
819///
820/// Since the REPLACEMENT CHARACTER fits into one UTF-16 code unit, the
821/// return value of this method applies also in the
822/// `_without_replacement` case.
823///
824/// # Undefined behavior
825///
826/// UB ensues if `decoder` is `NULL`.
827#[no_mangle]
828pub unsafe extern "C" fn decoder_max_utf16_buffer_length(
829    decoder: *const Decoder,
830    u16_length: usize,
831) -> usize {
832    (*decoder)
833        .max_utf16_buffer_length(u16_length)
834        .unwrap_or(::std::usize::MAX)
835}
836
837/// Incrementally decode a byte stream into UTF-16 with malformed sequences
838/// replaced with the REPLACEMENT CHARACTER.
839///
840/// See the top-level FFI documentation for documentation for how the
841/// `decoder_decode_*` functions are mapped from Rust and the documentation
842/// for the [`Decoder`][1] struct for the semantics.
843///
844/// `src` must be non-`NULL` even if `src_len` is zero. When`src_len` is zero,
845/// it is OK for `src` to be something non-dereferencable, such as `0x1`.
846/// Likewise for `dst` when `dst_len` is zero. This is required due to Rust's
847/// optimization for slices within `Option`.
848///
849/// # Undefined behavior
850///
851/// UB ensues if any of the pointer arguments is `NULL`, `src` and `src_len`
852/// don't designate a valid block of memory or `dst` and `dst_len` don't
853/// designate a valid block of memory.
854///
855/// [1]: https://docs.rs/encoding_rs/0.6.10/encoding_rs/struct.Decoder.html
856#[no_mangle]
857pub unsafe extern "C" fn decoder_decode_to_utf16(
858    decoder: *mut Decoder,
859    src: *const u8,
860    src_len: *mut usize,
861    dst: *mut u16,
862    dst_len: *mut usize,
863    last: bool,
864    had_replacements: *mut bool,
865) -> u32 {
866    let src_slice = ::std::slice::from_raw_parts(src, *src_len);
867    let dst_slice = ::std::slice::from_raw_parts_mut(dst, *dst_len);
868    let (result, read, written, replaced) = (*decoder).decode_to_utf16(src_slice, dst_slice, last);
869    *src_len = read;
870    *dst_len = written;
871    *had_replacements = replaced;
872    coder_result_to_u32(result)
873}
874
875/// Incrementally decode a byte stream into UTF-16 _without replacement_.
876///
877/// See the top-level FFI documentation for documentation for how the
878/// `decoder_decode_*` functions are mapped from Rust and the documentation
879/// for the [`Decoder`][1] struct for the semantics.
880///
881/// `src` must be non-`NULL` even if `src_len` is zero. When`src_len` is zero,
882/// it is OK for `src` to be something non-dereferencable, such as `0x1`.
883/// Likewise for `dst` when `dst_len` is zero. This is required due to Rust's
884/// optimization for slices within `Option`.
885///
886/// # Undefined behavior
887///
888/// UB ensues if any of the pointer arguments is `NULL`, `src` and `src_len`
889/// don't designate a valid block of memory or `dst` and `dst_len` don't
890/// designate a valid block of memory.
891///
892/// [1]: https://docs.rs/encoding_rs/0.6.10/encoding_rs/struct.Decoder.html
893#[no_mangle]
894pub unsafe extern "C" fn decoder_decode_to_utf16_without_replacement(
895    decoder: *mut Decoder,
896    src: *const u8,
897    src_len: *mut usize,
898    dst: *mut u16,
899    dst_len: *mut usize,
900    last: bool,
901) -> u32 {
902    let src_slice = ::std::slice::from_raw_parts(src, *src_len);
903    let dst_slice = ::std::slice::from_raw_parts_mut(dst, *dst_len);
904    let (result, read, written) =
905        (*decoder).decode_to_utf16_without_replacement(src_slice, dst_slice, last);
906    *src_len = read;
907    *dst_len = written;
908    decoder_result_to_u32(result)
909}
910
911/// Checks for compatibility with storing Unicode scalar values as unsigned
912/// bytes taking into account the state of the decoder.
913///
914/// Returns `SIZE_MAX` if the decoder is not in a neutral state, including waiting
915/// for the BOM, or if the encoding is never Latin1-byte-compatible.
916///
917/// Otherwise returns the index of the first byte whose unsigned value doesn't
918/// directly correspond to the decoded Unicode scalar value, or the length
919/// of the input if all bytes in the input decode directly to scalar values
920/// corresponding to the unsigned byte values.
921///
922/// Does not change the state of the decoder.
923///
924/// Do not use this unless you are supporting SpiderMonkey/V8-style string
925/// storage optimizations.
926///
927/// # Undefined behavior
928///
929/// UB ensues if `buffer` and `*buffer_len` don't designate a valid memory
930/// block of if `buffer` is `NULL`.
931#[no_mangle]
932pub unsafe extern "C" fn decoder_latin1_byte_compatible_up_to(
933    decoder: *const Decoder,
934    buffer: *const u8,
935    buffer_len: usize,
936) -> usize {
937    (*decoder)
938        .latin1_byte_compatible_up_to(::std::slice::from_raw_parts(buffer, buffer_len))
939        .unwrap_or(::std::usize::MAX)
940}
941
942/// Deallocates an `Encoder` previously allocated by `encoding_new_encoder()`.
943///
944/// # Undefined behavior
945///
946/// UB ensues if the argument is `NULL`.
947#[no_mangle]
948pub unsafe extern "C" fn encoder_free(encoder: *mut Encoder) {
949    let _ = Box::from_raw(encoder);
950}
951
952/// The `Encoding` this `Encoder` is for.
953///
954/// # Undefined behavior
955///
956/// UB ensues if the argument is `NULL`.
957#[no_mangle]
958pub unsafe extern "C" fn encoder_encoding(encoder: *const Encoder) -> *const Encoding {
959    (*encoder).encoding()
960}
961
962/// Returns `true` if this is an ISO-2022-JP encoder that's not in the
963/// ASCII state and `false` otherwise.
964///
965/// # Undefined behavior
966///
967/// UB ensues if the argument is `NULL`.
968#[no_mangle]
969pub unsafe extern "C" fn encoder_has_pending_state(encoder: *const Encoder) -> bool {
970    (*encoder).has_pending_state()
971}
972
973/// Query the worst-case output size when encoding from UTF-8 with
974/// replacement.
975///
976/// Returns the size of the output buffer in bytes that will not overflow
977/// given the current state of the encoder and `byte_length` number of
978/// additional input code units if there are no unmappable characters in
979/// the input or `SIZE_MAX` if `size_t` would overflow.
980#[no_mangle]
981pub unsafe extern "C" fn encoder_max_buffer_length_from_utf8_if_no_unmappables(
982    encoder: *const Encoder,
983    byte_length: usize,
984) -> usize {
985    (*encoder)
986        .max_buffer_length_from_utf8_if_no_unmappables(byte_length)
987        .unwrap_or(::std::usize::MAX)
988}
989
990/// Query the worst-case output size when encoding from UTF-8 without
991/// replacement.
992///
993/// Returns the size of the output buffer in bytes that will not overflow
994/// given the current state of the encoder and `byte_length` number of
995/// additional input code units or `SIZE_MAX` if `size_t` would overflow.
996#[no_mangle]
997pub unsafe extern "C" fn encoder_max_buffer_length_from_utf8_without_replacement(
998    encoder: *const Encoder,
999    byte_length: usize,
1000) -> usize {
1001    (*encoder)
1002        .max_buffer_length_from_utf8_without_replacement(byte_length)
1003        .unwrap_or(::std::usize::MAX)
1004}
1005
1006/// Incrementally encode into byte stream from UTF-8 with unmappable
1007/// characters replaced with HTML (decimal) numeric character references.
1008///
1009/// The input absolutely _MUST_ be valid UTF-8 or the behavior is memory-unsafe!
1010/// If in doubt, check the validity of input before using!
1011///
1012/// See the top-level FFI documentation for documentation for how the
1013/// `encoder_encode_*` functions are mapped from Rust and the documentation
1014/// for the [`Encoder`][1] struct for the semantics.
1015///
1016/// `src` must be non-`NULL` even if `src_len` is zero. When`src_len` is zero,
1017/// it is OK for `src` to be something non-dereferencable, such as `0x1`.
1018/// Likewise for `dst` when `dst_len` is zero. This is required due to Rust's
1019/// optimization for slices within `Option`.
1020///
1021/// # Undefined behavior
1022///
1023/// UB ensues if any of the pointer arguments is `NULL`, `src` and `src_len`
1024/// don't designate a valid block of memory or `dst` and `dst_len` don't
1025/// designate a valid block of memory.
1026///
1027/// [1]: https://docs.rs/encoding_rs/0.6.10/encoding_rs/struct.Encoder.html
1028#[no_mangle]
1029pub unsafe extern "C" fn encoder_encode_from_utf8(
1030    encoder: *mut Encoder,
1031    src: *const u8,
1032    src_len: *mut usize,
1033    dst: *mut u8,
1034    dst_len: *mut usize,
1035    last: bool,
1036    had_replacements: *mut bool,
1037) -> u32 {
1038    let src_slice = ::std::slice::from_raw_parts(src, *src_len);
1039    let string = ::std::str::from_utf8_unchecked(src_slice);
1040    let dst_slice = ::std::slice::from_raw_parts_mut(dst, *dst_len);
1041    let (result, read, written, replaced) = (*encoder).encode_from_utf8(string, dst_slice, last);
1042    *src_len = read;
1043    *dst_len = written;
1044    *had_replacements = replaced;
1045    coder_result_to_u32(result)
1046}
1047
1048/// Incrementally encode into byte stream from UTF-8 _without replacement_.
1049///
1050/// See the top-level FFI documentation for documentation for how the
1051/// `encoder_encode_*` functions are mapped from Rust and the documentation
1052/// for the [`Encoder`][1] struct for the semantics.
1053///
1054/// The input absolutely _MUST_ be valid UTF-8 or the behavior is memory-unsafe!
1055/// If in doubt, check the validity of input before using!
1056///
1057/// `src` must be non-`NULL` even if `src_len` is zero. When`src_len` is zero,
1058/// it is OK for `src` to be something non-dereferencable, such as `0x1`.
1059/// Likewise for `dst` when `dst_len` is zero. This is required due to Rust's
1060/// optimization for slices within `Option`.
1061///
1062/// # Undefined behavior
1063///
1064/// UB ensues if any of the pointer arguments is `NULL`, `src` and `src_len`
1065/// don't designate a valid block of memory or `dst` and `dst_len` don't
1066/// designate a valid block of memory.
1067///
1068/// [1]: https://docs.rs/encoding_rs/0.6.10/encoding_rs/struct.Encoder.html
1069#[no_mangle]
1070pub unsafe extern "C" fn encoder_encode_from_utf8_without_replacement(
1071    encoder: *mut Encoder,
1072    src: *const u8,
1073    src_len: *mut usize,
1074    dst: *mut u8,
1075    dst_len: *mut usize,
1076    last: bool,
1077) -> u32 {
1078    let src_slice = ::std::slice::from_raw_parts(src, *src_len);
1079    let string = ::std::str::from_utf8_unchecked(src_slice);
1080    let dst_slice = ::std::slice::from_raw_parts_mut(dst, *dst_len);
1081    let (result, read, written) =
1082        (*encoder).encode_from_utf8_without_replacement(string, dst_slice, last);
1083    *src_len = read;
1084    *dst_len = written;
1085    encoder_result_to_u32(result)
1086}
1087
1088/// Query the worst-case output size when encoding from UTF-16 with
1089/// replacement.
1090///
1091/// Returns the size of the output buffer in bytes that will not overflow
1092/// given the current state of the encoder and `u16_length` number of
1093/// additional input code units if there are no unmappable characters in
1094/// the input or `SIZE_MAX` if `size_t` would overflow.
1095#[no_mangle]
1096pub unsafe extern "C" fn encoder_max_buffer_length_from_utf16_if_no_unmappables(
1097    encoder: *const Encoder,
1098    u16_length: usize,
1099) -> usize {
1100    (*encoder)
1101        .max_buffer_length_from_utf16_if_no_unmappables(u16_length)
1102        .unwrap_or(::std::usize::MAX)
1103}
1104
1105/// Query the worst-case output size when encoding from UTF-16 without
1106/// replacement.
1107///
1108/// Returns the size of the output buffer in bytes that will not overflow
1109/// given the current state of the encoder and `u16_length` number of
1110/// additional input code units or `SIZE_MAX` if `size_t` would overflow.
1111#[no_mangle]
1112pub unsafe extern "C" fn encoder_max_buffer_length_from_utf16_without_replacement(
1113    encoder: *const Encoder,
1114    u16_length: usize,
1115) -> usize {
1116    (*encoder)
1117        .max_buffer_length_from_utf16_without_replacement(u16_length)
1118        .unwrap_or(::std::usize::MAX)
1119}
1120
1121/// Incrementally encode into byte stream from UTF-16 with unmappable
1122/// characters replaced with HTML (decimal) numeric character references.
1123///
1124/// See the top-level FFI documentation for documentation for how the
1125/// `encoder_encode_*` functions are mapped from Rust and the documentation
1126/// for the [`Encoder`][1] struct for the semantics.
1127///
1128/// `src` must be non-`NULL` even if `src_len` is zero. When`src_len` is zero,
1129/// it is OK for `src` to be something non-dereferencable, such as `0x1`.
1130/// Likewise for `dst` when `dst_len` is zero. This is required due to Rust's
1131/// optimization for slices within `Option`.
1132///
1133/// # Undefined behavior
1134///
1135/// UB ensues if any of the pointer arguments is `NULL`, `src` and `src_len`
1136/// don't designate a valid block of memory or `dst` and `dst_len` don't
1137/// designate a valid block of memory.
1138///
1139/// [1]: https://docs.rs/encoding_rs/0.6.10/encoding_rs/struct.Encoder.html
1140#[no_mangle]
1141pub unsafe extern "C" fn encoder_encode_from_utf16(
1142    encoder: *mut Encoder,
1143    src: *const u16,
1144    src_len: *mut usize,
1145    dst: *mut u8,
1146    dst_len: *mut usize,
1147    last: bool,
1148    had_replacements: *mut bool,
1149) -> u32 {
1150    let src_slice = ::std::slice::from_raw_parts(src, *src_len);
1151    let dst_slice = ::std::slice::from_raw_parts_mut(dst, *dst_len);
1152    let (result, read, written, replaced) =
1153        (*encoder).encode_from_utf16(src_slice, dst_slice, last);
1154    *src_len = read;
1155    *dst_len = written;
1156    *had_replacements = replaced;
1157    coder_result_to_u32(result)
1158}
1159
1160/// Incrementally encode into byte stream from UTF-16 _without replacement_.
1161///
1162/// See the top-level FFI documentation for documentation for how the
1163/// `encoder_encode_*` functions are mapped from Rust and the documentation
1164/// for the [`Encoder`][1] struct for the semantics.
1165///
1166/// `src` must be non-`NULL` even if `src_len` is zero. When`src_len` is zero,
1167/// it is OK for `src` to be something non-dereferencable, such as `0x1`.
1168/// Likewise for `dst` when `dst_len` is zero. This is required due to Rust's
1169/// optimization for slices within `Option`.
1170///
1171/// # Undefined behavior
1172///
1173/// UB ensues if any of the pointer arguments is `NULL`, `src` and `src_len`
1174/// don't designate a valid block of memory or `dst` and `dst_len` don't
1175/// designate a valid block of memory.
1176///
1177/// [1]: https://docs.rs/encoding_rs/0.6.10/encoding_rs/struct.Encoder.html
1178#[no_mangle]
1179pub unsafe extern "C" fn encoder_encode_from_utf16_without_replacement(
1180    encoder: *mut Encoder,
1181    src: *const u16,
1182    src_len: *mut usize,
1183    dst: *mut u8,
1184    dst_len: *mut usize,
1185    last: bool,
1186) -> u32 {
1187    let src_slice = ::std::slice::from_raw_parts(src, *src_len);
1188    let dst_slice = ::std::slice::from_raw_parts_mut(dst, *dst_len);
1189    let (result, read, written) =
1190        (*encoder).encode_from_utf16_without_replacement(src_slice, dst_slice, last);
1191    *src_len = read;
1192    *dst_len = written;
1193    encoder_result_to_u32(result)
1194}