1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4 
5 //! This module provides rust bindings for the XPCOM string types.
6 //!
7 //! # TL;DR (what types should I use)
8 //!
9 //! Use `&{mut,} nsA[C]String` for functions in rust which wish to take or
10 //! mutate XPCOM strings. The other string types `Deref` to this type.
11 //!
12 //! Use `ns[C]String` (`ns[C]String` in C++) for string struct members, and as
13 //! an intermediate between rust string data structures (such as `String` or
14 //! `Vec<u16>`) and `&{mut,} nsA[C]String` (using `ns[C]String::from(value)`).
15 //! These conversions will attempt to re-use the passed-in buffer, appending a
16 //! null.
17 //!
18 //! Use `ns[C]Str` (`nsDependent[C]String` in C++) as an intermediate between
19 //! borrowed rust data structures (such as `&str` and `&[u16]`) and `&{mut,}
20 //! nsA[C]String` (using `ns[C]Str::from(value)`). These conversions should not
21 //! perform any allocations. This type is not safe to share with `C++` as a
22 //! struct field, but passing the borrowed `&{mut,} nsA[C]String` over FFI is
23 //! safe.
24 //!
25 //! Use `*{const,mut} nsA[C]String` (`{const,} nsA[C]String*` in C++) for
26 //! function arguments passed across the rust/C++ language boundary.
27 //!
28 //! There is currently no Rust equivalent to nsAuto[C]String. Implementing a
29 //! type that contains a pointer to an inline buffer is difficult in Rust due
30 //! to its move semantics, which require that it be safe to move a value by
31 //! copying its bits. If such a type is genuinely needed at some point,
32 //! https://bugzilla.mozilla.org/show_bug.cgi?id=1403506#c6 has a sketch of how
33 //! to emulate it via macros.
34 //!
35 //! # String Types
36 //!
37 //! ## `nsA[C]String`
38 //!
39 //! The core types in this module are `nsAString` and `nsACString`. These types
40 //! are zero-sized as far as rust is concerned, and are safe to pass around
41 //! behind both references (in rust code), and pointers (in C++ code). They
42 //! represent a handle to a XPCOM string which holds either `u16` or `u8`
43 //! characters respectively. The backing character buffer is guaranteed to live
44 //! as long as the reference to the `nsAString` or `nsACString`.
45 //!
46 //! These types in rust are simply used as dummy types. References to them
47 //! represent a pointer to the beginning of a variable-sized `#[repr(C)]` struct
48 //! which is common between both C++ and Rust implementations. In C++, their
49 //! corresponding types are also named `nsAString` or `nsACString`, and they are
50 //! defined within the `nsTSubstring.{cpp,h}` file.
51 //!
52 //! ### Valid Operations
53 //!
54 //! An `&nsA[C]String` acts like rust's `&str`, in that it is a borrowed
55 //! reference to the backing data. When used as an argument to other functions
56 //! on `&mut nsA[C]String`, optimizations can be performed to avoid copying
57 //! buffers, as information about the backing storage is preserved.
58 //!
59 //! An `&mut nsA[C]String` acts like rust's `&mut Cow<str>`, in that it is a
60 //! mutable reference to a potentially borrowed string, which when modified will
61 //! ensure that it owns its own backing storage. This type can be appended to
62 //! with the methods `.append`, `.append_utf{8,16}`, and with the `write!`
63 //! macro, and can be assigned to with `.assign`.
64 //!
65 //! ## `ns[C]Str<'a>`
66 //!
67 //! This type is an maybe-owned string type. It acts similarially to a
68 //! `Cow<[{u8,u16}]>`. This type provides `Deref` and `DerefMut` implementations
69 //! to `nsA[C]String`, which provides the methods for manipulating this type.
70 //! This type's lifetime parameter, `'a`, represents the lifetime of the backing
71 //! storage. When modified this type may re-allocate in order to ensure that it
72 //! does not mutate its backing storage.
73 //!
74 //! `ns[C]Str`s can be constructed either with `ns[C]Str::new()`, which creates
75 //! an empty `ns[C]Str<'static>`, or through one of the provided `From`
76 //! implementations. Only `nsCStr` can be constructed `From<'a str>`, as
77 //! constructing a `nsStr` would require transcoding. Use `ns[C]String` instead.
78 //!
79 //! When passing this type by reference, prefer passing a `&nsA[C]String` or
80 //! `&mut nsA[C]String`. to passing this type.
81 //!
82 //! When passing this type across the language boundary, pass it as `*const
83 //! nsA[C]String` for an immutable reference, or `*mut nsA[C]String` for a
84 //! mutable reference.
85 //!
86 //! ## `ns[C]String`
87 //!
88 //! This type is an owned, null-terminated string type. This type provides
89 //! `Deref` and `DerefMut` implementations to `nsA[C]String`, which provides the
90 //! methods for manipulating this type.
91 //!
92 //! `ns[C]String`s can be constructed either with `ns[C]String::new()`, which
93 //! creates an empty `ns[C]String`, or through one of the provided `From`
94 //! implementations, which will try to avoid reallocating when possible,
95 //! although a terminating `null` will be added.
96 //!
97 //! When passing this type by reference, prefer passing a `&nsA[C]String` or
98 //! `&mut nsA[C]String`. to passing this type.
99 //!
100 //! When passing this type across the language boundary, pass it as `*const
101 //! nsA[C]String` for an immutable reference, or `*mut nsA[C]String` for a
102 //! mutable reference. This struct may also be included in `#[repr(C)]` structs
103 //! shared with C++.
104 //!
105 //! ## `ns[C]StringRepr`
106 //!
107 //! This crate also provides the type `ns[C]StringRepr` which acts conceptually
108 //! similar to an `ns[C]String`, however, it does not have a `Drop`
109 //! implementation.
110 //!
111 //! If this type is dropped in rust, it will not free its backing storage. This
112 //! can be useful when implementing FFI types which contain `ns[C]String` members
113 //! which invoke their member's destructors through C++ code.
114 
115 #![allow(non_camel_case_types)]
116 
117 #[macro_use]
118 extern crate bitflags;
119 
120 use std::borrow;
121 use std::cmp;
122 use std::fmt;
123 use std::marker::PhantomData;
124 use std::mem;
125 use std::ops::{Deref, DerefMut};
126 use std::os::raw::c_void;
127 use std::ptr;
128 use std::slice;
129 use std::str;
130 use std::u32;
131 
132 mod conversions;
133 
134 pub use self::conversions::nscstring_fallible_append_latin1_to_utf8_check;
135 pub use self::conversions::nscstring_fallible_append_utf16_to_latin1_lossy_impl;
136 pub use self::conversions::nscstring_fallible_append_utf16_to_utf8_impl;
137 pub use self::conversions::nscstring_fallible_append_utf8_to_latin1_lossy_check;
138 pub use self::conversions::nsstring_fallible_append_latin1_impl;
139 pub use self::conversions::nsstring_fallible_append_utf8_impl;
140 
141 /// A type for showing that `finish()` was called on a `BulkWriteHandle`.
142 /// Instantiating this type from elsewhere is basically an assertion that
143 /// there is no `BulkWriteHandle` around, so be very careful with instantiating
144 /// this type!
145 pub struct BulkWriteOk;
146 
147 /// Semi-arbitrary threshold below which we don't care about shrinking
148 /// buffers to size. Currently matches `CACHE_LINE` in the `conversions`
149 /// module.
150 const SHRINKING_THRESHOLD: usize = 64;
151 
152 ///////////////////////////////////
153 // Internal Implementation Flags //
154 ///////////////////////////////////
155 
156 mod data_flags {
157     bitflags! {
158         // While this has the same layout as u16, it cannot be passed
159         // over FFI safely as a u16.
160         #[repr(C)]
161         pub struct DataFlags: u16 {
162             const TERMINATED = 1 << 0; // IsTerminated returns true
163             const VOIDED = 1 << 1; // IsVoid returns true
164             const REFCOUNTED = 1 << 2; // mData points to a heap-allocated, shareable, refcounted
165                                        // buffer
166             const OWNED = 1 << 3; // mData points to a heap-allocated, raw buffer
167             const INLINE = 1 << 4; // mData points to a writable, inline buffer
168             const LITERAL = 1 << 5; // mData points to a string literal; TERMINATED will also be set
169         }
170     }
171 }
172 
173 mod class_flags {
174     bitflags! {
175         // While this has the same layout as u16, it cannot be passed
176         // over FFI safely as a u16.
177         #[repr(C)]
178         pub struct ClassFlags: u16 {
179             const INLINE = 1 << 0; // |this|'s buffer is inline
180             const NULL_TERMINATED = 1 << 1; // |this| requires its buffer is null-terminated
181         }
182     }
183 }
184 
185 use class_flags::ClassFlags;
186 use data_flags::DataFlags;
187 
188 ////////////////////////////////////
189 // Generic String Bindings Macros //
190 ////////////////////////////////////
191 
192 macro_rules! string_like {
193     {
194         char_t = $char_t: ty;
195 
196         AString = $AString: ident;
197         String = $String: ident;
198         Str = $Str: ident;
199 
200         StringLike = $StringLike: ident;
201         StringAdapter = $StringAdapter: ident;
202     } => {
203         /// This trait is implemented on types which are `ns[C]String`-like, in
204         /// that they can at very low cost be converted to a borrowed
205         /// `&nsA[C]String`. Unfortunately, the intermediate type
206         /// `ns[C]StringAdapter` is required as well due to types like `&[u8]`
207         /// needing to be (cheaply) wrapped in a `nsCString` on the stack to
208         /// create the `&nsACString`.
209         ///
210         /// This trait is used to DWIM when calling the methods on
211         /// `nsA[C]String`.
212         pub trait $StringLike {
213             fn adapt(&self) -> $StringAdapter;
214         }
215 
216         impl<'a, T: $StringLike + ?Sized> $StringLike for &'a T {
217             fn adapt(&self) -> $StringAdapter {
218                 <T as $StringLike>::adapt(*self)
219             }
220         }
221 
222         impl<'a, T> $StringLike for borrow::Cow<'a, T>
223             where T: $StringLike + borrow::ToOwned + ?Sized {
224             fn adapt(&self) -> $StringAdapter {
225                 <T as $StringLike>::adapt(self.as_ref())
226             }
227         }
228 
229         impl $StringLike for $AString {
230             fn adapt(&self) -> $StringAdapter {
231                 $StringAdapter::Abstract(self)
232             }
233         }
234 
235         impl<'a> $StringLike for $Str<'a> {
236             fn adapt(&self) -> $StringAdapter {
237                 $StringAdapter::Abstract(self)
238             }
239         }
240 
241         impl $StringLike for $String {
242             fn adapt(&self) -> $StringAdapter {
243                 $StringAdapter::Abstract(self)
244             }
245         }
246 
247         impl $StringLike for [$char_t] {
248             fn adapt(&self) -> $StringAdapter {
249                 $StringAdapter::Borrowed($Str::from(self))
250             }
251         }
252 
253         impl $StringLike for Vec<$char_t> {
254             fn adapt(&self) -> $StringAdapter {
255                 $StringAdapter::Borrowed($Str::from(&self[..]))
256             }
257         }
258 
259         impl $StringLike for Box<[$char_t]> {
260             fn adapt(&self) -> $StringAdapter {
261                 $StringAdapter::Borrowed($Str::from(&self[..]))
262             }
263         }
264     }
265 }
266 
267 impl<'a> Drop for nsAStringBulkWriteHandle<'a> {
268     /// This only runs in error cases. In success cases, `finish()`
269     /// calls `forget(self)`.
drop(&mut self)270     fn drop(&mut self) {
271         if self.capacity == 0 {
272             // If capacity is 0, the string is a zero-length
273             // string, so we have nothing to do.
274             return;
275         }
276         // The old zero terminator may be gone by now, so we need
277         // to write a new one somewhere and make length match.
278         // We can use a length between 1 and self.capacity.
279         // Seems prudent to overwrite the uninitialized memory.
280         // Using the length 1 leaves the shortest memory to overwrite.
281         // U+FFFD is the safest placeholder. Merely truncating the
282         // string to a zero-length string might be dangerous in some
283         // scenarios. See
284         // https://www.unicode.org/reports/tr36/#Substituting_for_Ill_Formed_Subsequences
285         // for closely related scenario.
286         unsafe {
287             let mut this = self.string.as_repr_mut();
288             this.as_mut().length = 1u32;
289             *(this.as_mut().data.as_mut()) = 0xFFFDu16;
290             *(this.as_mut().data.as_ptr().offset(1isize)) = 0;
291         }
292     }
293 }
294 
295 impl<'a> Drop for nsACStringBulkWriteHandle<'a> {
296     /// This only runs in error cases. In success cases, `finish()`
297     /// calls `forget(self)`.
drop(&mut self)298     fn drop(&mut self) {
299         if self.capacity == 0 {
300             // If capacity is 0, the string is a zero-length
301             // string, so we have nothing to do.
302             return;
303         }
304         // The old zero terminator may be gone by now, so we need
305         // to write a new one somewhere and make length match.
306         // We can use a length between 1 and self.capacity.
307         // Seems prudent to overwrite the uninitialized memory.
308         // Using the length 1 leaves the shortest memory to overwrite.
309         // U+FFFD is the safest placeholder, but when it doesn't fit,
310         // let's use ASCII substitute. Merely truncating the
311         // string to a zero-length string might be dangerous in some
312         // scenarios. See
313         // https://www.unicode.org/reports/tr36/#Substituting_for_Ill_Formed_Subsequences
314         // for closely related scenario.
315         unsafe {
316             let mut this = self.string.as_repr_mut();
317             if self.capacity >= 3 {
318                 this.as_mut().length = 3u32;
319                 *(this.as_mut().data.as_mut()) = 0xEFu8;
320                 *(this.as_mut().data.as_ptr().offset(1isize)) = 0xBFu8;
321                 *(this.as_mut().data.as_ptr().offset(2isize)) = 0xBDu8;
322                 *(this.as_mut().data.as_ptr().offset(3isize)) = 0;
323             } else {
324                 this.as_mut().length = 1u32;
325                 *(this.as_mut().data.as_mut()) = 0x1Au8; // U+FFFD doesn't fit
326                 *(this.as_mut().data.as_ptr().offset(1isize)) = 0;
327             }
328         }
329     }
330 }
331 
332 macro_rules! define_string_types {
333     {
334         char_t = $char_t: ty;
335 
336         AString = $AString: ident;
337         String = $String: ident;
338         Str = $Str: ident;
339 
340         StringLike = $StringLike: ident;
341         StringAdapter = $StringAdapter: ident;
342 
343         StringRepr = $StringRepr: ident;
344         AutoStringRepr = $AutoStringRepr: ident;
345 
346         BulkWriteHandle = $BulkWriteHandle: ident;
347 
348         drop = $drop: ident;
349         assign = $assign: ident, $fallible_assign: ident;
350         take_from = $take_from: ident, $fallible_take_from: ident;
351         append = $append: ident, $fallible_append: ident;
352         set_length = $set_length: ident, $fallible_set_length: ident;
353         begin_writing = $begin_writing: ident, $fallible_begin_writing: ident;
354         start_bulk_write = $start_bulk_write: ident;
355     } => {
356         /// The representation of a ns[C]String type in C++. This type is
357         /// used internally by our definition of ns[C]String to ensure layout
358         /// compatibility with the C++ ns[C]String type.
359         ///
360         /// This type may also be used in place of a C++ ns[C]String inside of
361         /// struct definitions which are shared with C++, as it has identical
362         /// layout to our ns[C]String type.
363         ///
364         /// This struct will leak its data if dropped from rust. See the module
365         /// documentation for more information on this type.
366         #[repr(C)]
367         #[derive(Debug)]
368         pub struct $StringRepr {
369             data: ptr::NonNull<$char_t>,
370             length: u32,
371             dataflags: DataFlags,
372             classflags: ClassFlags,
373         }
374 
375         impl $StringRepr {
376             fn new(classflags: ClassFlags) -> $StringRepr {
377                 static NUL: $char_t = 0;
378                 $StringRepr {
379                     data: unsafe { ptr::NonNull::new_unchecked(&NUL as *const _ as *mut _) },
380                     length: 0,
381                     dataflags: DataFlags::TERMINATED | DataFlags::LITERAL,
382                     classflags,
383                 }
384             }
385         }
386 
387         impl Deref for $StringRepr {
388             type Target = $AString;
389             fn deref(&self) -> &$AString {
390                 unsafe {
391                     mem::transmute(self)
392                 }
393             }
394         }
395 
396         impl DerefMut for $StringRepr {
397             fn deref_mut(&mut self) -> &mut $AString {
398                 unsafe {
399                     mem::transmute(self)
400                 }
401             }
402         }
403 
404         #[repr(C)]
405         #[derive(Debug)]
406         pub struct $AutoStringRepr {
407             super_repr: $StringRepr,
408             inline_capacity: u32,
409         }
410 
411         pub struct $BulkWriteHandle<'a> {
412             string: &'a mut $AString,
413             capacity: usize,
414         }
415 
416         impl<'a> $BulkWriteHandle<'a> {
417             fn new(string: &'a mut $AString, capacity: usize) -> Self {
418                 $BulkWriteHandle{ string, capacity }
419             }
420 
421             pub unsafe fn restart_bulk_write(&mut self,
422                                              capacity: usize,
423                                              units_to_preserve: usize,
424                                              allow_shrinking: bool) -> Result<(), ()> {
425                 self.capacity =
426                     self.string.start_bulk_write_impl(capacity,
427                                                       units_to_preserve,
428                                                       allow_shrinking)?;
429                 Ok(())
430             }
431 
432             pub fn finish(mut self, length: usize, allow_shrinking: bool) -> BulkWriteOk {
433                 // NOTE: Drop is implemented outside the macro earlier in this file,
434                 // because it needs to deal with different code unit representations
435                 // for the REPLACEMENT CHARACTER in the UTF-16 and UTF-8 cases and
436                 // needs to deal with a REPLACEMENT CHARACTER not fitting in the
437                 // buffer in the UTF-8 case.
438                 assert!(length <= self.capacity);
439                 if length == 0 {
440                     // `truncate()` is OK even when the string
441                     // is in invalid state.
442                     self.string.truncate();
443                     mem::forget(self); // Don't run the failure path in drop()
444                     return BulkWriteOk{};
445                 }
446                 if allow_shrinking && length > SHRINKING_THRESHOLD {
447                     unsafe {
448                         let _ = self.restart_bulk_write(length, length, true);
449                     }
450                 }
451                 unsafe {
452                     let mut this = self.string.as_repr_mut();
453                     this.as_mut().length = length as u32;
454                     *(this.as_mut().data.as_ptr().offset(length as isize)) = 0;
455                     if cfg!(debug_assertions) {
456                         // Overwrite the unused part in debug builds. Note
457                         // that capacity doesn't include space for the zero
458                         // terminator, so starting after the zero-terminator
459                         // we wrote ends up overwriting the terminator space
460                         // not reflected in the capacity number.
461                         // write_bytes() takes care of multiplying the length
462                         // by the size of T.
463                         ptr::write_bytes(this.as_mut().data.as_ptr().offset((length + 1) as isize),
464                                          0xE4u8,
465                                          self.capacity - length);
466                     }
467                     // We don't have a Rust interface for mozilla/MemoryChecking.h,
468                     // so let's just not communicate with MSan/Valgrind here.
469                 }
470                 mem::forget(self); // Don't run the failure path in drop()
471                 BulkWriteOk{}
472             }
473 
474             pub fn as_mut_slice(&mut self) -> &mut [$char_t] {
475                 unsafe {
476                     let mut this = self.string.as_repr_mut();
477                     slice::from_raw_parts_mut(this.as_mut().data.as_ptr(), self.capacity)
478                 }
479             }
480         }
481 
482         /// This type is the abstract type which is used for interacting with
483         /// strings in rust. Each string type can derefence to an instance of
484         /// this type, which provides the useful operations on strings.
485         ///
486         /// NOTE: Rust thinks this type has a size of 0, because the data
487         /// associated with it is not necessarially safe to move. It is not safe
488         /// to construct a nsAString yourself, unless it is received by
489         /// dereferencing one of these types.
490         ///
491         /// NOTE: The `[u8; 0]` member is zero sized, and only exists to prevent
492         /// the construction by code outside of this module. It is used instead
493         /// of a private `()` member because the `improper_ctypes` lint complains
494         /// about some ZST members in `extern "C"` function declarations.
495         #[repr(C)]
496         pub struct $AString {
497             _prohibit_constructor: [u8; 0],
498         }
499 
500         impl $AString {
501             /// Assign the value of `other` into self, overwriting any value
502             /// currently stored. Performs an optimized assignment when possible
503             /// if `other` is a `nsA[C]String`.
504             pub fn assign<T: $StringLike + ?Sized>(&mut self, other: &T) {
505                 unsafe { $assign(self, other.adapt().as_ptr()) };
506             }
507 
508             /// Assign the value of `other` into self, overwriting any value
509             /// currently stored. Performs an optimized assignment when possible
510             /// if `other` is a `nsA[C]String`.
511             ///
512             /// Returns Ok(()) on success, and Err(()) if the allocation failed.
513             pub fn fallible_assign<T: $StringLike + ?Sized>(&mut self, other: &T) -> Result<(), ()> {
514                 if unsafe { $fallible_assign(self, other.adapt().as_ptr()) } {
515                     Ok(())
516                 } else {
517                     Err(())
518                 }
519             }
520 
521             /// Take the value of `other` and set `self`, overwriting any value
522             /// currently stored. The passed-in string will be truncated.
523             pub fn take_from(&mut self, other: &mut $AString) {
524                 unsafe { $take_from(self, other) };
525             }
526 
527             /// Take the value of `other` and set `self`, overwriting any value
528             /// currently stored. If this function fails, the source string will
529             /// be left untouched, otherwise it will be truncated.
530             ///
531             /// Returns Ok(()) on success, and Err(()) if the allocation failed.
532             pub fn fallible_take_from(&mut self, other: &mut $AString) -> Result<(), ()> {
533                 if unsafe { $fallible_take_from(self, other) } {
534                     Ok(())
535                 } else {
536                     Err(())
537                 }
538             }
539 
540             /// Append the value of `other` into self.
541             pub fn append<T: $StringLike + ?Sized>(&mut self, other: &T) {
542                 unsafe { $append(self, other.adapt().as_ptr()) };
543             }
544 
545             /// Append the value of `other` into self.
546             ///
547             /// Returns Ok(()) on success, and Err(()) if the allocation failed.
548             pub fn fallible_append<T: $StringLike + ?Sized>(&mut self, other: &T) -> Result<(), ()> {
549                 if unsafe { $fallible_append(self, other.adapt().as_ptr()) } {
550                     Ok(())
551                 } else {
552                     Err(())
553                 }
554             }
555 
556             /// Set the length of the string to the passed-in length, and expand
557             /// the backing capacity to match. This method is unsafe as it can
558             /// expose uninitialized memory when len is greater than the current
559             /// length of the string.
560             pub unsafe fn set_length(&mut self, len: u32) {
561                 $set_length(self, len);
562             }
563 
564             /// Set the length of the string to the passed-in length, and expand
565             /// the backing capacity to match. This method is unsafe as it can
566             /// expose uninitialized memory when len is greater than the current
567             /// length of the string.
568             ///
569             /// Returns Ok(()) on success, and Err(()) if the allocation failed.
570             pub unsafe fn fallible_set_length(&mut self, len: u32) -> Result<(), ()> {
571                 if $fallible_set_length(self, len) {
572                     Ok(())
573                 } else {
574                     Err(())
575                 }
576             }
577 
578             pub fn truncate(&mut self) {
579                 unsafe {
580                     self.set_length(0);
581                 }
582             }
583 
584             /// Get a `&mut` reference to the backing data for this string.
585             /// This method will allocate and copy if the current backing buffer
586             /// is immutable or shared.
587             pub fn to_mut(&mut self) -> &mut [$char_t] {
588                 unsafe {
589                     let len = self.len();
590                     if len == 0 {
591                         // Use an arbitrary but aligned non-null value as the pointer
592                         slice::from_raw_parts_mut(ptr::NonNull::<$char_t>::dangling().as_ptr(), 0)
593                     } else {
594                         slice::from_raw_parts_mut($begin_writing(self), len)
595                     }
596                 }
597             }
598 
599             /// Get a `&mut` reference to the backing data for this string.
600             /// This method will allocate and copy if the current backing buffer
601             /// is immutable or shared.
602             ///
603             /// Returns `Ok(&mut [T])` on success, and `Err(())` if the
604             /// allocation failed.
605             pub fn fallible_to_mut(&mut self) -> Result<&mut [$char_t], ()> {
606                 unsafe {
607                     let len = self.len();
608                     if len == 0 {
609                         // Use an arbitrary but aligned non-null value as the pointer
610                         Ok(slice::from_raw_parts_mut(
611                             ptr::NonNull::<$char_t>::dangling().as_ptr() as *mut $char_t, 0))
612                     } else {
613                         let ptr = $fallible_begin_writing(self);
614                         if ptr.is_null() {
615                             Err(())
616                         } else {
617                             Ok(slice::from_raw_parts_mut(ptr, len))
618                         }
619                     }
620                 }
621             }
622 
623             /// Unshares the buffer of the string and returns a handle
624             /// from which a writable slice whose length is the rounded-up
625             /// capacity can be obtained.
626             ///
627             /// Fails also if the new length doesn't fit in 32 bits.
628             ///
629             /// # Safety
630             ///
631             /// Unsafe because of exposure of uninitialized memory.
632             pub unsafe fn bulk_write(&mut self,
633                                      capacity: usize,
634                                      units_to_preserve: usize,
635                                      allow_shrinking: bool) -> Result<$BulkWriteHandle, ()> {
636                 let capacity =
637                     self.start_bulk_write_impl(capacity, units_to_preserve, allow_shrinking)?;
638                 Ok($BulkWriteHandle::new(self, capacity))
639             }
640 
641             unsafe fn start_bulk_write_impl(&mut self,
642                                             capacity: usize,
643                                             units_to_preserve: usize,
644                                             allow_shrinking: bool) -> Result<usize, ()> {
645                 if capacity > u32::max_value() as usize {
646                     Err(())
647                 } else {
648                     let capacity32 = capacity as u32;
649                     let rounded = $start_bulk_write(self,
650                                                     capacity32,
651                                                     units_to_preserve as u32,
652                                                     allow_shrinking && capacity > SHRINKING_THRESHOLD);
653                     if rounded == u32::max_value() {
654                         return Err(())
655                     }
656                     Ok(rounded as usize)
657                 }
658             }
659 
660             fn as_repr(&self) -> &$StringRepr {
661                 // All $AString values point to a struct prefix which is
662                 // identical to $StringRepr, this we can transmute `self`
663                 // into $StringRepr to get the reference to the underlying
664                 // data.
665                 unsafe {
666                     &*(self as *const _ as *const $StringRepr)
667                 }
668             }
669 
670             fn as_repr_mut(&mut self) -> ptr::NonNull<$StringRepr> {
671                 unsafe { ptr::NonNull::new_unchecked(self as *mut _ as *mut $StringRepr)}
672             }
673 
674             fn as_auto_string_repr(&self) -> Option<&$AutoStringRepr> {
675                 if !self.as_repr().classflags.contains(ClassFlags::INLINE) {
676                     return None;
677                 }
678 
679                 unsafe {
680                     Some(&*(self as *const _ as *const $AutoStringRepr))
681                 }
682             }
683 
684             /// If this is an autostring, returns the capacity (excluding the
685             /// zero terminator) of the inline buffer within `Some()`. Otherwise
686             /// returns `None`.
687             pub fn inline_capacity(&self) -> Option<usize> {
688                 Some(self.as_auto_string_repr()?.inline_capacity as usize)
689             }
690         }
691 
692         impl Deref for $AString {
693             type Target = [$char_t];
694             fn deref(&self) -> &[$char_t] {
695                 unsafe {
696                     // All $AString values point to a struct prefix which is
697                     // identical to $StringRepr, this we can transmute `self`
698                     // into $StringRepr to get the reference to the underlying
699                     // data.
700                     let this: &$StringRepr = mem::transmute(self);
701                     slice::from_raw_parts(this.data.as_ptr(), this.length as usize)
702                 }
703             }
704         }
705 
706         impl AsRef<[$char_t]> for $AString {
707             fn as_ref(&self) -> &[$char_t] {
708                 self
709             }
710         }
711 
712         impl cmp::PartialEq for $AString {
713             fn eq(&self, other: &$AString) -> bool {
714                 &self[..] == &other[..]
715             }
716         }
717 
718         impl cmp::PartialEq<[$char_t]> for $AString {
719             fn eq(&self, other: &[$char_t]) -> bool {
720                 &self[..] == other
721             }
722         }
723 
724         impl cmp::PartialEq<$String> for $AString {
725             fn eq(&self, other: &$String) -> bool {
726                 self.eq(&**other)
727             }
728         }
729 
730         impl<'a> cmp::PartialEq<$Str<'a>> for $AString {
731             fn eq(&self, other: &$Str<'a>) -> bool {
732                 self.eq(&**other)
733             }
734         }
735 
736         #[repr(C)]
737         pub struct $Str<'a> {
738             hdr: $StringRepr,
739             _marker: PhantomData<&'a [$char_t]>,
740         }
741 
742         impl $Str<'static> {
743             pub fn new() -> $Str<'static> {
744                 $Str {
745                     hdr: $StringRepr::new(ClassFlags::empty()),
746                     _marker: PhantomData,
747                 }
748             }
749         }
750 
751         impl<'a> Drop for $Str<'a> {
752             fn drop(&mut self) {
753                 unsafe {
754                     $drop(&mut **self);
755                 }
756             }
757         }
758 
759         impl<'a> Deref for $Str<'a> {
760             type Target = $AString;
761             fn deref(&self) -> &$AString {
762                 &self.hdr
763             }
764         }
765 
766         impl<'a> DerefMut for $Str<'a> {
767             fn deref_mut(&mut self) -> &mut $AString {
768                 &mut self.hdr
769             }
770         }
771 
772         impl<'a> AsRef<[$char_t]> for $Str<'a> {
773             fn as_ref(&self) -> &[$char_t] {
774                 &self
775             }
776         }
777 
778         impl<'a> From<&'a [$char_t]> for $Str<'a> {
779             fn from(s: &'a [$char_t]) -> $Str<'a> {
780                 assert!(s.len() < (u32::MAX as usize));
781                 if s.is_empty() {
782                     return $Str::new();
783                 }
784                 $Str {
785                     hdr: $StringRepr {
786                         data: unsafe { ptr::NonNull::new_unchecked(s.as_ptr() as *mut _) },
787                         length: s.len() as u32,
788                         dataflags: DataFlags::empty(),
789                         classflags: ClassFlags::empty(),
790                     },
791                     _marker: PhantomData,
792                 }
793             }
794         }
795 
796         impl<'a> From<&'a Vec<$char_t>> for $Str<'a> {
797             fn from(s: &'a Vec<$char_t>) -> $Str<'a> {
798                 $Str::from(&s[..])
799             }
800         }
801 
802         impl<'a> From<&'a $AString> for $Str<'a> {
803             fn from(s: &'a $AString) -> $Str<'a> {
804                 $Str::from(&s[..])
805             }
806         }
807 
808         impl<'a> fmt::Write for $Str<'a> {
809             fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
810                 $AString::write_str(self, s)
811             }
812         }
813 
814         impl<'a> fmt::Display for $Str<'a> {
815             fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
816                 <$AString as fmt::Display>::fmt(self, f)
817             }
818         }
819 
820         impl<'a> fmt::Debug for $Str<'a> {
821             fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
822                 <$AString as fmt::Debug>::fmt(self, f)
823             }
824         }
825 
826         impl<'a> cmp::PartialEq for $Str<'a> {
827             fn eq(&self, other: &$Str<'a>) -> bool {
828                 $AString::eq(self, other)
829             }
830         }
831 
832         impl<'a> cmp::PartialEq<[$char_t]> for $Str<'a> {
833             fn eq(&self, other: &[$char_t]) -> bool {
834                 $AString::eq(self, other)
835             }
836         }
837 
838         impl<'a, 'b> cmp::PartialEq<&'b [$char_t]> for $Str<'a> {
839             fn eq(&self, other: &&'b [$char_t]) -> bool {
840                 $AString::eq(self, *other)
841             }
842         }
843 
844         impl<'a> cmp::PartialEq<str> for $Str<'a> {
845             fn eq(&self, other: &str) -> bool {
846                 $AString::eq(self, other)
847             }
848         }
849 
850         impl<'a, 'b> cmp::PartialEq<&'b str> for $Str<'a> {
851             fn eq(&self, other: &&'b str) -> bool {
852                 $AString::eq(self, *other)
853             }
854         }
855 
856         #[repr(C)]
857         pub struct $String {
858             hdr: $StringRepr,
859         }
860 
861         unsafe impl Send for $String {}
862         unsafe impl Sync for $String {}
863 
864         impl $String {
865             pub fn new() -> $String {
866                 $String {
867                     hdr: $StringRepr::new(ClassFlags::NULL_TERMINATED),
868                 }
869             }
870 
871             /// Converts this String into a StringRepr, which will leak if the
872             /// repr is not passed to something that knows how to free it.
873             pub fn into_repr(mut self) -> $StringRepr {
874                 mem::replace(&mut self.hdr, $StringRepr::new(ClassFlags::NULL_TERMINATED))
875             }
876         }
877 
878         impl Drop for $String {
879             fn drop(&mut self) {
880                 unsafe {
881                     $drop(&mut **self);
882                 }
883             }
884         }
885 
886         impl Deref for $String {
887             type Target = $AString;
888             fn deref(&self) -> &$AString {
889                 &self.hdr
890             }
891         }
892 
893         impl DerefMut for $String {
894             fn deref_mut(&mut self) -> &mut $AString {
895                 &mut self.hdr
896             }
897         }
898 
899         impl Clone for $String {
900             fn clone(&self) -> Self {
901                 let mut copy = $String::new();
902                 copy.assign(self);
903                 copy
904             }
905         }
906 
907         impl AsRef<[$char_t]> for $String {
908             fn as_ref(&self) -> &[$char_t] {
909                 &self
910             }
911         }
912 
913         impl<'a> From<&'a [$char_t]> for $String {
914             fn from(s: &'a [$char_t]) -> $String {
915                 let mut res = $String::new();
916                 res.assign(&$Str::from(&s[..]));
917                 res
918             }
919         }
920 
921         impl<'a> From<&'a Vec<$char_t>> for $String {
922             fn from(s: &'a Vec<$char_t>) -> $String {
923                 $String::from(&s[..])
924             }
925         }
926 
927         impl<'a> From<&'a $AString> for $String {
928             fn from(s: &'a $AString) -> $String {
929                 $String::from(&s[..])
930             }
931         }
932 
933         impl From<Box<[$char_t]>> for $String {
934             fn from(s: Box<[$char_t]>) -> $String {
935                 s.into_vec().into()
936             }
937         }
938 
939         impl From<Vec<$char_t>> for $String {
940             fn from(mut s: Vec<$char_t>) -> $String {
941                 assert!(s.len() < (u32::MAX as usize));
942                 if s.is_empty() {
943                     return $String::new();
944                 }
945 
946                 let length = s.len() as u32;
947                 s.push(0); // null terminator
948 
949                 // SAFETY NOTE: This method produces an data_flags::OWNED
950                 // ns[C]String from a Box<[$char_t]>. this is only safe
951                 // because in the Gecko tree, we use the same allocator for
952                 // Rust code as for C++ code, meaning that our box can be
953                 // legally freed with libc::free().
954                 let ptr = s.as_mut_ptr();
955                 mem::forget(s);
956                 unsafe {
957                     Gecko_IncrementStringAdoptCount(ptr as *mut _);
958                 }
959                 $String {
960                     hdr: $StringRepr {
961                         data: unsafe { ptr::NonNull::new_unchecked(ptr) },
962                         length: length,
963                         dataflags: DataFlags::OWNED | DataFlags::TERMINATED,
964                         classflags: ClassFlags::NULL_TERMINATED,
965                     }
966                 }
967             }
968         }
969 
970         impl fmt::Write for $String {
971             fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
972                 $AString::write_str(self, s)
973             }
974         }
975 
976         impl fmt::Display for $String {
977             fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
978                 <$AString as fmt::Display>::fmt(self, f)
979             }
980         }
981 
982         impl fmt::Debug for $String {
983             fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
984                 <$AString as fmt::Debug>::fmt(self, f)
985             }
986         }
987 
988         impl cmp::PartialEq for $String {
989             fn eq(&self, other: &$String) -> bool {
990                 $AString::eq(self, other)
991             }
992         }
993 
994         impl cmp::PartialEq<[$char_t]> for $String {
995             fn eq(&self, other: &[$char_t]) -> bool {
996                 $AString::eq(self, other)
997             }
998         }
999 
1000         impl<'a> cmp::PartialEq<&'a [$char_t]> for $String {
1001             fn eq(&self, other: &&'a [$char_t]) -> bool {
1002                 $AString::eq(self, *other)
1003             }
1004         }
1005 
1006         impl cmp::PartialEq<str> for $String {
1007             fn eq(&self, other: &str) -> bool {
1008                 $AString::eq(self, other)
1009             }
1010         }
1011 
1012         impl<'a> cmp::PartialEq<&'a str> for $String {
1013             fn eq(&self, other: &&'a str) -> bool {
1014                 $AString::eq(self, *other)
1015             }
1016         }
1017 
1018         /// An adapter type to allow for passing both types which coerce to
1019         /// &[$char_type], and &$AString to a function, while still performing
1020         /// optimized operations when passed the $AString.
1021         pub enum $StringAdapter<'a> {
1022             Borrowed($Str<'a>),
1023             Abstract(&'a $AString),
1024         }
1025 
1026         impl<'a> $StringAdapter<'a> {
1027             fn as_ptr(&self) -> *const $AString {
1028                 &**self
1029             }
1030         }
1031 
1032         impl<'a> Deref for $StringAdapter<'a> {
1033             type Target = $AString;
1034 
1035             fn deref(&self) -> &$AString {
1036                 match *self {
1037                     $StringAdapter::Borrowed(ref s) => s,
1038                     $StringAdapter::Abstract(ref s) => s,
1039                 }
1040             }
1041         }
1042 
1043         impl<'a> $StringAdapter<'a> {
1044             #[allow(dead_code)]
1045             fn is_abstract(&self) -> bool {
1046                 match *self {
1047                     $StringAdapter::Borrowed(_) => false,
1048                     $StringAdapter::Abstract(_) => true,
1049                 }
1050             }
1051         }
1052 
1053         string_like! {
1054             char_t = $char_t;
1055 
1056             AString = $AString;
1057             String = $String;
1058             Str = $Str;
1059 
1060             StringLike = $StringLike;
1061             StringAdapter = $StringAdapter;
1062         }
1063     }
1064 }
1065 
1066 ///////////////////////////////////////////
1067 // Bindings for nsCString (u8 char type) //
1068 ///////////////////////////////////////////
1069 
1070 define_string_types! {
1071     char_t = u8;
1072 
1073     AString = nsACString;
1074     String = nsCString;
1075     Str = nsCStr;
1076 
1077     StringLike = nsCStringLike;
1078     StringAdapter = nsCStringAdapter;
1079 
1080     StringRepr = nsCStringRepr;
1081     AutoStringRepr = nsAutoCStringRepr;
1082 
1083     BulkWriteHandle = nsACStringBulkWriteHandle;
1084 
1085     drop = Gecko_FinalizeCString;
1086     assign = Gecko_AssignCString, Gecko_FallibleAssignCString;
1087     take_from = Gecko_TakeFromCString, Gecko_FallibleTakeFromCString;
1088     append = Gecko_AppendCString, Gecko_FallibleAppendCString;
1089     set_length = Gecko_SetLengthCString, Gecko_FallibleSetLengthCString;
1090     begin_writing = Gecko_BeginWritingCString, Gecko_FallibleBeginWritingCString;
1091     start_bulk_write = Gecko_StartBulkWriteCString;
1092 }
1093 
1094 impl nsACString {
1095     /// Gets a CString as an utf-8 str or a String, trying to avoid copies, and
1096     /// replacing invalid unicode sequences with replacement characters.
1097     #[inline]
to_utf8(&self) -> borrow::Cow<str>1098     pub fn to_utf8(&self) -> borrow::Cow<str> {
1099         String::from_utf8_lossy(&self[..])
1100     }
1101 
1102     #[inline]
as_str_unchecked(&self) -> &str1103     pub unsafe fn as_str_unchecked(&self) -> &str {
1104         if cfg!(debug_assertions) {
1105             str::from_utf8(self).expect("Should be utf-8")
1106         } else {
1107             str::from_utf8_unchecked(self)
1108         }
1109     }
1110 }
1111 
1112 impl<'a> From<&'a str> for nsCStr<'a> {
from(s: &'a str) -> nsCStr<'a>1113     fn from(s: &'a str) -> nsCStr<'a> {
1114         s.as_bytes().into()
1115     }
1116 }
1117 
1118 impl<'a> From<&'a String> for nsCStr<'a> {
from(s: &'a String) -> nsCStr<'a>1119     fn from(s: &'a String) -> nsCStr<'a> {
1120         nsCStr::from(&s[..])
1121     }
1122 }
1123 
1124 impl<'a> From<&'a str> for nsCString {
from(s: &'a str) -> nsCString1125     fn from(s: &'a str) -> nsCString {
1126         s.as_bytes().into()
1127     }
1128 }
1129 
1130 impl<'a> From<&'a String> for nsCString {
from(s: &'a String) -> nsCString1131     fn from(s: &'a String) -> nsCString {
1132         nsCString::from(&s[..])
1133     }
1134 }
1135 
1136 impl From<Box<str>> for nsCString {
from(s: Box<str>) -> nsCString1137     fn from(s: Box<str>) -> nsCString {
1138         s.into_string().into()
1139     }
1140 }
1141 
1142 impl From<String> for nsCString {
from(s: String) -> nsCString1143     fn from(s: String) -> nsCString {
1144         s.into_bytes().into()
1145     }
1146 }
1147 
1148 // Support for the write!() macro for appending to nsACStrings
1149 impl fmt::Write for nsACString {
write_str(&mut self, s: &str) -> Result<(), fmt::Error>1150     fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
1151         self.append(s);
1152         Ok(())
1153     }
1154 }
1155 
1156 impl fmt::Display for nsACString {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>1157     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
1158         fmt::Display::fmt(&self.to_utf8(), f)
1159     }
1160 }
1161 
1162 impl fmt::Debug for nsACString {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>1163     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
1164         fmt::Debug::fmt(&self.to_utf8(), f)
1165     }
1166 }
1167 
1168 impl cmp::PartialEq<str> for nsACString {
eq(&self, other: &str) -> bool1169     fn eq(&self, other: &str) -> bool {
1170         &self[..] == other.as_bytes()
1171     }
1172 }
1173 
1174 impl nsCStringLike for str {
adapt(&self) -> nsCStringAdapter1175     fn adapt(&self) -> nsCStringAdapter {
1176         nsCStringAdapter::Borrowed(nsCStr::from(self))
1177     }
1178 }
1179 
1180 impl nsCStringLike for String {
adapt(&self) -> nsCStringAdapter1181     fn adapt(&self) -> nsCStringAdapter {
1182         nsCStringAdapter::Borrowed(nsCStr::from(&self[..]))
1183     }
1184 }
1185 
1186 impl nsCStringLike for Box<str> {
adapt(&self) -> nsCStringAdapter1187     fn adapt(&self) -> nsCStringAdapter {
1188         nsCStringAdapter::Borrowed(nsCStr::from(&self[..]))
1189     }
1190 }
1191 
1192 // This trait is implemented on types which are Latin1 `nsCString`-like,
1193 // in that they can at very low cost be converted to a borrowed
1194 // `&nsACString` and do not denote UTF-8ness in the Rust type system.
1195 //
1196 // This trait is used to DWIM when calling the methods on
1197 // `nsACString`.
1198 string_like! {
1199     char_t = u8;
1200 
1201     AString = nsACString;
1202     String = nsCString;
1203     Str = nsCStr;
1204 
1205     StringLike = Latin1StringLike;
1206     StringAdapter = nsCStringAdapter;
1207 }
1208 
1209 ///////////////////////////////////////////
1210 // Bindings for nsString (u16 char type) //
1211 ///////////////////////////////////////////
1212 
1213 define_string_types! {
1214     char_t = u16;
1215 
1216     AString = nsAString;
1217     String = nsString;
1218     Str = nsStr;
1219 
1220     StringLike = nsStringLike;
1221     StringAdapter = nsStringAdapter;
1222 
1223     StringRepr = nsStringRepr;
1224     AutoStringRepr = nsAutoStringRepr;
1225 
1226     BulkWriteHandle = nsAStringBulkWriteHandle;
1227 
1228     drop = Gecko_FinalizeString;
1229     assign = Gecko_AssignString, Gecko_FallibleAssignString;
1230     take_from = Gecko_TakeFromString, Gecko_FallibleTakeFromString;
1231     append = Gecko_AppendString, Gecko_FallibleAppendString;
1232     set_length = Gecko_SetLengthString, Gecko_FallibleSetLengthString;
1233     begin_writing = Gecko_BeginWritingString, Gecko_FallibleBeginWritingString;
1234     start_bulk_write = Gecko_StartBulkWriteString;
1235 }
1236 
1237 // NOTE: The From impl for a string slice for nsString produces a <'static>
1238 // lifetime, as it allocates.
1239 impl<'a> From<&'a str> for nsString {
from(s: &'a str) -> nsString1240     fn from(s: &'a str) -> nsString {
1241         s.encode_utf16().collect::<Vec<u16>>().into()
1242     }
1243 }
1244 
1245 impl<'a> From<&'a String> for nsString {
from(s: &'a String) -> nsString1246     fn from(s: &'a String) -> nsString {
1247         nsString::from(&s[..])
1248     }
1249 }
1250 
1251 // Support for the write!() macro for writing to nsStrings
1252 impl fmt::Write for nsAString {
write_str(&mut self, s: &str) -> Result<(), fmt::Error>1253     fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
1254         // Directly invoke gecko's routines for appending utf8 strings to
1255         // nsAString values, to avoid as much overhead as possible
1256         self.append_str(s);
1257         Ok(())
1258     }
1259 }
1260 
1261 impl nsAString {
1262     /// Turns this utf-16 string into a string, replacing invalid unicode
1263     /// sequences with replacement characters.
1264     ///
1265     /// This is needed because the default ToString implementation goes through
1266     /// fmt::Display, and thus allocates the string twice.
to_string(&self) -> String1267     pub fn to_string(&self) -> String {
1268         String::from_utf16_lossy(&self[..])
1269     }
1270 }
1271 
1272 impl fmt::Display for nsAString {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>1273     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
1274         fmt::Display::fmt(&self.to_string(), f)
1275     }
1276 }
1277 
1278 impl fmt::Debug for nsAString {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>1279     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
1280         fmt::Debug::fmt(&self.to_string(), f)
1281     }
1282 }
1283 
1284 impl cmp::PartialEq<str> for nsAString {
eq(&self, other: &str) -> bool1285     fn eq(&self, other: &str) -> bool {
1286         other.encode_utf16().eq(self.iter().cloned())
1287     }
1288 }
1289 
1290 #[cfg(not(feature = "gecko_debug"))]
1291 #[allow(non_snake_case)]
Gecko_IncrementStringAdoptCount(_: *mut c_void)1292 unsafe fn Gecko_IncrementStringAdoptCount(_: *mut c_void) {}
1293 
1294 extern "C" {
1295     #[cfg(feature = "gecko_debug")]
Gecko_IncrementStringAdoptCount(data: *mut c_void)1296     fn Gecko_IncrementStringAdoptCount(data: *mut c_void);
1297 
1298     // Gecko implementation in nsSubstring.cpp
Gecko_FinalizeCString(this: *mut nsACString)1299     fn Gecko_FinalizeCString(this: *mut nsACString);
1300 
Gecko_AssignCString(this: *mut nsACString, other: *const nsACString)1301     fn Gecko_AssignCString(this: *mut nsACString, other: *const nsACString);
Gecko_TakeFromCString(this: *mut nsACString, other: *mut nsACString)1302     fn Gecko_TakeFromCString(this: *mut nsACString, other: *mut nsACString);
Gecko_AppendCString(this: *mut nsACString, other: *const nsACString)1303     fn Gecko_AppendCString(this: *mut nsACString, other: *const nsACString);
Gecko_SetLengthCString(this: *mut nsACString, length: u32)1304     fn Gecko_SetLengthCString(this: *mut nsACString, length: u32);
Gecko_BeginWritingCString(this: *mut nsACString) -> *mut u81305     fn Gecko_BeginWritingCString(this: *mut nsACString) -> *mut u8;
Gecko_FallibleAssignCString(this: *mut nsACString, other: *const nsACString) -> bool1306     fn Gecko_FallibleAssignCString(this: *mut nsACString, other: *const nsACString) -> bool;
Gecko_FallibleTakeFromCString(this: *mut nsACString, other: *mut nsACString) -> bool1307     fn Gecko_FallibleTakeFromCString(this: *mut nsACString, other: *mut nsACString) -> bool;
Gecko_FallibleAppendCString(this: *mut nsACString, other: *const nsACString) -> bool1308     fn Gecko_FallibleAppendCString(this: *mut nsACString, other: *const nsACString) -> bool;
Gecko_FallibleSetLengthCString(this: *mut nsACString, length: u32) -> bool1309     fn Gecko_FallibleSetLengthCString(this: *mut nsACString, length: u32) -> bool;
Gecko_FallibleBeginWritingCString(this: *mut nsACString) -> *mut u81310     fn Gecko_FallibleBeginWritingCString(this: *mut nsACString) -> *mut u8;
Gecko_StartBulkWriteCString( this: *mut nsACString, capacity: u32, units_to_preserve: u32, allow_shrinking: bool, ) -> u321311     fn Gecko_StartBulkWriteCString(
1312         this: *mut nsACString,
1313         capacity: u32,
1314         units_to_preserve: u32,
1315         allow_shrinking: bool,
1316     ) -> u32;
1317 
Gecko_FinalizeString(this: *mut nsAString)1318     fn Gecko_FinalizeString(this: *mut nsAString);
1319 
Gecko_AssignString(this: *mut nsAString, other: *const nsAString)1320     fn Gecko_AssignString(this: *mut nsAString, other: *const nsAString);
Gecko_TakeFromString(this: *mut nsAString, other: *mut nsAString)1321     fn Gecko_TakeFromString(this: *mut nsAString, other: *mut nsAString);
Gecko_AppendString(this: *mut nsAString, other: *const nsAString)1322     fn Gecko_AppendString(this: *mut nsAString, other: *const nsAString);
Gecko_SetLengthString(this: *mut nsAString, length: u32)1323     fn Gecko_SetLengthString(this: *mut nsAString, length: u32);
Gecko_BeginWritingString(this: *mut nsAString) -> *mut u161324     fn Gecko_BeginWritingString(this: *mut nsAString) -> *mut u16;
Gecko_FallibleAssignString(this: *mut nsAString, other: *const nsAString) -> bool1325     fn Gecko_FallibleAssignString(this: *mut nsAString, other: *const nsAString) -> bool;
Gecko_FallibleTakeFromString(this: *mut nsAString, other: *mut nsAString) -> bool1326     fn Gecko_FallibleTakeFromString(this: *mut nsAString, other: *mut nsAString) -> bool;
Gecko_FallibleAppendString(this: *mut nsAString, other: *const nsAString) -> bool1327     fn Gecko_FallibleAppendString(this: *mut nsAString, other: *const nsAString) -> bool;
Gecko_FallibleSetLengthString(this: *mut nsAString, length: u32) -> bool1328     fn Gecko_FallibleSetLengthString(this: *mut nsAString, length: u32) -> bool;
Gecko_FallibleBeginWritingString(this: *mut nsAString) -> *mut u161329     fn Gecko_FallibleBeginWritingString(this: *mut nsAString) -> *mut u16;
Gecko_StartBulkWriteString( this: *mut nsAString, capacity: u32, units_to_preserve: u32, allow_shrinking: bool, ) -> u321330     fn Gecko_StartBulkWriteString(
1331         this: *mut nsAString,
1332         capacity: u32,
1333         units_to_preserve: u32,
1334         allow_shrinking: bool,
1335     ) -> u32;
1336 }
1337 
1338 //////////////////////////////////////
1339 // Repr Validation Helper Functions //
1340 //////////////////////////////////////
1341 
1342 pub mod test_helpers {
1343     //! This module only exists to help with ensuring that the layout of the
1344     //! structs inside of rust and C++ are identical.
1345     //!
1346     //! It is public to ensure that these testing functions are avaliable to
1347     //! gtest code.
1348 
1349     use super::{nsACString, nsAString};
1350     use super::{nsCStr, nsCString, nsCStringRepr};
1351     use super::{nsStr, nsString, nsStringRepr};
1352     use super::{ClassFlags, DataFlags};
1353     use std::mem;
1354 
1355     /// Generates an #[no_mangle] extern "C" function which returns the size and
1356     /// alignment of the given type with the given name.
1357     macro_rules! size_align_check {
1358         ($T:ty, $fname:ident) => {
1359             #[no_mangle]
1360             #[allow(non_snake_case)]
1361             pub extern "C" fn $fname(size: *mut usize, align: *mut usize) {
1362                 unsafe {
1363                     *size = mem::size_of::<$T>();
1364                     *align = mem::align_of::<$T>();
1365                 }
1366             }
1367         };
1368         ($T:ty, $U:ty, $V:ty, $fname:ident) => {
1369             #[no_mangle]
1370             #[allow(non_snake_case)]
1371             pub extern "C" fn $fname(size: *mut usize, align: *mut usize) {
1372                 unsafe {
1373                     *size = mem::size_of::<$T>();
1374                     *align = mem::align_of::<$T>();
1375 
1376                     assert_eq!(*size, mem::size_of::<$U>());
1377                     assert_eq!(*align, mem::align_of::<$U>());
1378                     assert_eq!(*size, mem::size_of::<$V>());
1379                     assert_eq!(*align, mem::align_of::<$V>());
1380                 }
1381             }
1382         };
1383     }
1384 
1385     size_align_check!(
1386         nsStringRepr,
1387         nsString,
1388         nsStr<'static>,
1389         Rust_Test_ReprSizeAlign_nsString
1390     );
1391     size_align_check!(
1392         nsCStringRepr,
1393         nsCString,
1394         nsCStr<'static>,
1395         Rust_Test_ReprSizeAlign_nsCString
1396     );
1397 
1398     /// Generates a $[no_mangle] extern "C" function which returns the size,
1399     /// alignment and offset in the parent struct of a given member, with the
1400     /// given name.
1401     ///
1402     /// This method can trigger Undefined Behavior if the accessing the member
1403     /// $member on a given type would use that type's `Deref` implementation.
1404     macro_rules! member_check {
1405         ($T:ty, $U:ty, $V:ty, $member:ident, $method:ident) => {
1406             #[no_mangle]
1407             #[allow(non_snake_case)]
1408             pub extern "C" fn $method(size: *mut usize, align: *mut usize, offset: *mut usize) {
1409                 unsafe {
1410                     // Create a temporary value of type T to get offsets, sizes
1411                     // and alignments from.
1412                     let tmp: mem::MaybeUninit<$T> = mem::MaybeUninit::uninit();
1413                     // FIXME: This should use &raw references when available,
1414                     // this is technically UB as it creates a reference to
1415                     // uninitialized memory, but there's no better way to do
1416                     // this right now.
1417                     let tmp = &*tmp.as_ptr();
1418                     *size = mem::size_of_val(&tmp.$member);
1419                     *align = mem::align_of_val(&tmp.$member);
1420                     *offset = (&tmp.$member as *const _ as usize) - (tmp as *const $T as usize);
1421 
1422                     let tmp: mem::MaybeUninit<$U> = mem::MaybeUninit::uninit();
1423                     let tmp = &*tmp.as_ptr();
1424                     assert_eq!(*size, mem::size_of_val(&tmp.hdr.$member));
1425                     assert_eq!(*align, mem::align_of_val(&tmp.hdr.$member));
1426                     assert_eq!(
1427                         *offset,
1428                         (&tmp.hdr.$member as *const _ as usize) - (tmp as *const $U as usize)
1429                     );
1430 
1431                     let tmp: mem::MaybeUninit<$V> = mem::MaybeUninit::uninit();
1432                     let tmp = &*tmp.as_ptr();
1433                     assert_eq!(*size, mem::size_of_val(&tmp.hdr.$member));
1434                     assert_eq!(*align, mem::align_of_val(&tmp.hdr.$member));
1435                     assert_eq!(
1436                         *offset,
1437                         (&tmp.hdr.$member as *const _ as usize) - (tmp as *const $V as usize)
1438                     );
1439                 }
1440             }
1441         };
1442     }
1443 
1444     member_check!(
1445         nsStringRepr,
1446         nsString,
1447         nsStr<'static>,
1448         data,
1449         Rust_Test_Member_nsString_mData
1450     );
1451     member_check!(
1452         nsStringRepr,
1453         nsString,
1454         nsStr<'static>,
1455         length,
1456         Rust_Test_Member_nsString_mLength
1457     );
1458     member_check!(
1459         nsStringRepr,
1460         nsString,
1461         nsStr<'static>,
1462         dataflags,
1463         Rust_Test_Member_nsString_mDataFlags
1464     );
1465     member_check!(
1466         nsStringRepr,
1467         nsString,
1468         nsStr<'static>,
1469         classflags,
1470         Rust_Test_Member_nsString_mClassFlags
1471     );
1472     member_check!(
1473         nsCStringRepr,
1474         nsCString,
1475         nsCStr<'static>,
1476         data,
1477         Rust_Test_Member_nsCString_mData
1478     );
1479     member_check!(
1480         nsCStringRepr,
1481         nsCString,
1482         nsCStr<'static>,
1483         length,
1484         Rust_Test_Member_nsCString_mLength
1485     );
1486     member_check!(
1487         nsCStringRepr,
1488         nsCString,
1489         nsCStr<'static>,
1490         dataflags,
1491         Rust_Test_Member_nsCString_mDataFlags
1492     );
1493     member_check!(
1494         nsCStringRepr,
1495         nsCString,
1496         nsCStr<'static>,
1497         classflags,
1498         Rust_Test_Member_nsCString_mClassFlags
1499     );
1500 
1501     #[no_mangle]
1502     #[allow(non_snake_case)]
Rust_Test_NsStringFlags( f_terminated: *mut u16, f_voided: *mut u16, f_refcounted: *mut u16, f_owned: *mut u16, f_inline: *mut u16, f_literal: *mut u16, f_class_inline: *mut u16, f_class_null_terminated: *mut u16, )1503     pub extern "C" fn Rust_Test_NsStringFlags(
1504         f_terminated: *mut u16,
1505         f_voided: *mut u16,
1506         f_refcounted: *mut u16,
1507         f_owned: *mut u16,
1508         f_inline: *mut u16,
1509         f_literal: *mut u16,
1510         f_class_inline: *mut u16,
1511         f_class_null_terminated: *mut u16,
1512     ) {
1513         unsafe {
1514             *f_terminated = DataFlags::TERMINATED.bits();
1515             *f_voided = DataFlags::VOIDED.bits();
1516             *f_refcounted = DataFlags::REFCOUNTED.bits();
1517             *f_owned = DataFlags::OWNED.bits();
1518             *f_inline = DataFlags::INLINE.bits();
1519             *f_literal = DataFlags::LITERAL.bits();
1520             *f_class_inline = ClassFlags::INLINE.bits();
1521             *f_class_null_terminated = ClassFlags::NULL_TERMINATED.bits();
1522         }
1523     }
1524 
1525     #[no_mangle]
1526     #[allow(non_snake_case)]
Rust_InlineCapacityFromRust( cstring: *const nsACString, string: *const nsAString, cstring_capacity: *mut usize, string_capacity: *mut usize, )1527     pub extern "C" fn Rust_InlineCapacityFromRust(
1528         cstring: *const nsACString,
1529         string: *const nsAString,
1530         cstring_capacity: *mut usize,
1531         string_capacity: *mut usize,
1532     ) {
1533         unsafe {
1534             *cstring_capacity = (*cstring).inline_capacity().unwrap();
1535             *string_capacity = (*string).inline_capacity().unwrap();
1536         }
1537     }
1538 }
1539