From ffcf92d8432f0f5205b25f50428799067fdb1c62 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 17 May 2018 10:46:44 -0500 Subject: [PATCH] Remove nsstring bindings --- Cargo.lock | 68 -- components/style/Cargo.toml | 5 +- support/gecko/nsstring/Cargo.toml | 13 - support/gecko/nsstring/src/lib.rs | 1214 ----------------------------- 4 files changed, 2 insertions(+), 1298 deletions(-) delete mode 100644 support/gecko/nsstring/Cargo.toml delete mode 100644 support/gecko/nsstring/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index fda43b567a4..caf486e514a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -584,24 +584,6 @@ dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cstr" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cstr-macros 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "procedural-masquerade 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cstr-macros" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "procedural-masquerade 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "darling" version = "0.4.0" @@ -991,25 +973,6 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "geckoservo" -version = "0.0.1" -dependencies = [ - "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cstr 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "malloc_size_of 0.0.1", - "nsstring 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.19.0", - "servo_arc 0.1.1", - "smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "style 0.0.1", - "style_traits 0.0.1", -] - [[package]] name = "getopts" version = "0.2.14" @@ -1976,13 +1939,6 @@ dependencies = [ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "nsstring" -version = "0.1.0" -dependencies = [ - "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num" version = "0.1.37" @@ -3042,7 +2998,6 @@ dependencies = [ "malloc_size_of 0.0.1", "malloc_size_of_derive 0.0.1", "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "nsstring 0.1.0", "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3123,27 +3078,6 @@ dependencies = [ "webrender_api 0.57.2 (git+https://github.com/servo/webrender)", ] -[[package]] -name = "stylo_tests" -version = "0.0.1" -dependencies = [ - "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cstr 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", - "geckoservo 0.0.1", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "malloc_size_of 0.0.1", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "selectors 0.19.0", - "size_of_test 0.0.1", - "smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "style 0.0.1", - "style_traits 0.0.1", -] - [[package]] name = "swapper" version = "0.1.0" @@ -3861,8 +3795,6 @@ dependencies = [ "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8a807ac3ab7a217829c2a3b65732b926b2befe6a35f33b4bf8b503692430f223" "checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df" -"checksum cstr 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bc6b738cea084b0bf479106e0089d58d8c3dbc35d1fef3c485e19e20ea47d252" -"checksum cstr-macros 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0472c17c83d3ec1af32fb6ee2b3ad56ae0b6e69355d63d1d30602055c34324a8" "checksum darling 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a78af487e4eb8f4421a1770687b328af6bb4494ca93435210678c6eea875c11" "checksum darling_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b315f49c7b6db3708bca6e6913c194581a44ec619b7a39e131d4dd63733a3698" "checksum darling_macro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eb69a38fdeaeaf3db712e1df170de67ee9dfc24fb88ca3e9d21e703ec25a4d8e" diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index 5ee9d3ead9a..f6089962b47 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -16,13 +16,13 @@ path = "lib.rs" doctest = false [features] -gecko = ["nsstring", "num_cpus", +gecko = ["num_cpus", "style_traits/gecko", "fallible/known_system_malloc"] use_bindgen = ["bindgen", "regex", "toml"] servo = ["serde", "style_traits/servo", "servo_atoms", "servo_config", "html5ever", "cssparser/serde", "encoding_rs", "malloc_size_of/servo", "arrayvec/use_union", "servo_url", "string_cache"] -gecko_debug = ["nsstring/gecko_debug"] +gecko_debug = [] [dependencies] app_units = "0.6" @@ -46,7 +46,6 @@ log = "0.4" malloc_size_of = { path = "../malloc_size_of" } malloc_size_of_derive = { path = "../malloc_size_of_derive" } matches = "0.1" -nsstring = {path = "../../support/gecko/nsstring", optional = true} num_cpus = {version = "1.1.0", optional = true} num-integer = "0.1.32" num-traits = "0.1.32" diff --git a/support/gecko/nsstring/Cargo.toml b/support/gecko/nsstring/Cargo.toml deleted file mode 100644 index 7ff13f1d9a6..00000000000 --- a/support/gecko/nsstring/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "nsstring" -version = "0.1.0" -authors = ["nobody@mozilla.com"] -license = "MPL-2.0" -description = "Rust bindings to xpcom string types" - -[features] -gecko_debug = [] - -[dependencies] -bitflags = "1.0" - diff --git a/support/gecko/nsstring/src/lib.rs b/support/gecko/nsstring/src/lib.rs deleted file mode 100644 index 8e96b9ef827..00000000000 --- a/support/gecko/nsstring/src/lib.rs +++ /dev/null @@ -1,1214 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -//! This module provides rust bindings for the XPCOM string types. -//! -//! # TL;DR (what types should I use) -//! -//! Use `&{mut,} nsA[C]String` for functions in rust which wish to take or -//! mutate XPCOM strings. The other string types `Deref` to this type. -//! -//! Use `ns[C]String` (`ns[C]String` in C++) for string struct members, and as -//! an intermediate between rust string data structures (such as `String` or -//! `Vec`) and `&{mut,} nsA[C]String` (using `ns[C]String::from(value)`). -//! These conversions will attempt to re-use the passed-in buffer, appending a -//! null. -//! -//! Use `ns[C]Str` (`nsDependent[C]String` in C++) as an intermediate between -//! borrowed rust data structures (such as `&str` and `&[u16]`) and `&{mut,} -//! nsA[C]String` (using `ns[C]Str::from(value)`). These conversions should not -//! perform any allocations. This type is not safe to share with `C++` as a -//! struct field, but passing the borrowed `&{mut,} nsA[C]String` over FFI is -//! safe. -//! -//! Use `*{const,mut} nsA[C]String` (`{const,} nsA[C]String*` in C++) for -//! function arguments passed across the rust/C++ language boundary. -//! -//! There is currently no Rust equivalent to nsAuto[C]String. Implementing a -//! type that contains a pointer to an inline buffer is difficult in Rust due -//! to its move semantics, which require that it be safe to move a value by -//! copying its bits. If such a type is genuinely needed at some point, -//! https://bugzilla.mozilla.org/show_bug.cgi?id=1403506#c6 has a sketch of how -//! to emulate it via macros. -//! -//! # String Types -//! -//! ## `nsA[C]String` -//! -//! The core types in this module are `nsAString` and `nsACString`. These types -//! are zero-sized as far as rust is concerned, and are safe to pass around -//! behind both references (in rust code), and pointers (in C++ code). They -//! represent a handle to a XPCOM string which holds either `u16` or `u8` -//! characters respectively. The backing character buffer is guaranteed to live -//! as long as the reference to the `nsAString` or `nsACString`. -//! -//! These types in rust are simply used as dummy types. References to them -//! represent a pointer to the beginning of a variable-sized `#[repr(C)]` struct -//! which is common between both C++ and Rust implementations. In C++, their -//! corresponding types are also named `nsAString` or `nsACString`, and they are -//! defined within the `nsTSubstring.{cpp,h}` file. -//! -//! ### Valid Operations -//! -//! An `&nsA[C]String` acts like rust's `&str`, in that it is a borrowed -//! reference to the backing data. When used as an argument to other functions -//! on `&mut nsA[C]String`, optimizations can be performed to avoid copying -//! buffers, as information about the backing storage is preserved. -//! -//! An `&mut nsA[C]String` acts like rust's `&mut Cow`, in that it is a -//! mutable reference to a potentially borrowed string, which when modified will -//! ensure that it owns its own backing storage. This type can be appended to -//! with the methods `.append`, `.append_utf{8,16}`, and with the `write!` -//! macro, and can be assigned to with `.assign`. -//! -//! ## `ns[C]Str<'a>` -//! -//! This type is an maybe-owned string type. It acts similarially to a -//! `Cow<[{u8,u16}]>`. This type provides `Deref` and `DerefMut` implementations -//! to `nsA[C]String`, which provides the methods for manipulating this type. -//! This type's lifetime parameter, `'a`, represents the lifetime of the backing -//! storage. When modified this type may re-allocate in order to ensure that it -//! does not mutate its backing storage. -//! -//! `ns[C]Str`s can be constructed either with `ns[C]Str::new()`, which creates -//! an empty `ns[C]Str<'static>`, or through one of the provided `From` -//! implementations. Only `nsCStr` can be constructed `From<'a str>`, as -//! constructing a `nsStr` would require transcoding. Use `ns[C]String` instead. -//! -//! When passing this type by reference, prefer passing a `&nsA[C]String` or -//! `&mut nsA[C]String`. to passing this type. -//! -//! When passing this type across the language boundary, pass it as `*const -//! nsA[C]String` for an immutable reference, or `*mut nsA[C]String` for a -//! mutable reference. -//! -//! ## `ns[C]String` -//! -//! This type is an owned, null-terminated string type. This type provides -//! `Deref` and `DerefMut` implementations to `nsA[C]String`, which provides the -//! methods for manipulating this type. -//! -//! `ns[C]String`s can be constructed either with `ns[C]String::new()`, which -//! creates an empty `ns[C]String`, or through one of the provided `From` -//! implementations, which will try to avoid reallocating when possible, -//! although a terminating `null` will be added. -//! -//! When passing this type by reference, prefer passing a `&nsA[C]String` or -//! `&mut nsA[C]String`. to passing this type. -//! -//! When passing this type across the language boundary, pass it as `*const -//! nsA[C]String` for an immutable reference, or `*mut nsA[C]String` for a -//! mutable reference. This struct may also be included in `#[repr(C)]` structs -//! shared with C++. -//! -//! ## `ns[C]StringRepr` -//! -//! This crate also provides the type `ns[C]StringRepr` which acts conceptually -//! similar to an `ns[C]String`, however, it does not have a `Drop` -//! implementation. -//! -//! If this type is dropped in rust, it will not free its backing storage. This -//! can be useful when implementing FFI types which contain `ns[C]String` members -//! which invoke their member's destructors through C++ code. - -#![allow(non_camel_case_types)] - -#[macro_use] -extern crate bitflags; - -use std::borrow; -use std::cmp; -use std::fmt; -use std::marker::PhantomData; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::os::raw::c_void; -use std::slice; -use std::str; -use std::u32; - -/////////////////////////////////// -// Internal Implementation Flags // -/////////////////////////////////// - -mod data_flags { - bitflags! { - // While this has the same layout as u16, it cannot be passed - // over FFI safely as a u16. - #[repr(C)] - pub struct DataFlags: u16 { - const TERMINATED = 1 << 0; // IsTerminated returns true - const VOIDED = 1 << 1; // IsVoid returns true - const REFCOUNTED = 1 << 2; // mData points to a heap-allocated, shareable, refcounted - // buffer - const OWNED = 1 << 3; // mData points to a heap-allocated, raw buffer - const INLINE = 1 << 4; // mData points to a writable, inline buffer - const LITERAL = 1 << 5; // mData points to a string literal; TERMINATED will also be set - } - } -} - -mod class_flags { - bitflags! { - // While this has the same layout as u16, it cannot be passed - // over FFI safely as a u16. - #[repr(C)] - pub struct ClassFlags: u16 { - const INLINE = 1 << 0; // |this|'s buffer is inline - const NULL_TERMINATED = 1 << 1; // |this| requires its buffer is null-terminated - } - } -} - -use class_flags::ClassFlags; -use data_flags::DataFlags; - -//////////////////////////////////// -// Generic String Bindings Macros // -//////////////////////////////////// - -macro_rules! define_string_types { - { - char_t = $char_t: ty; - - AString = $AString: ident; - String = $String: ident; - Str = $Str: ident; - - StringLike = $StringLike: ident; - StringAdapter = $StringAdapter: ident; - - StringRepr = $StringRepr: ident; - - drop = $drop: ident; - assign = $assign: ident, $fallible_assign: ident; - take_from = $take_from: ident, $fallible_take_from: ident; - append = $append: ident, $fallible_append: ident; - set_length = $set_length: ident, $fallible_set_length: ident; - begin_writing = $begin_writing: ident, $fallible_begin_writing: ident; - } => { - /// The representation of a ns[C]String type in C++. This type is - /// used internally by our definition of ns[C]String to ensure layout - /// compatibility with the C++ ns[C]String type. - /// - /// This type may also be used in place of a C++ ns[C]String inside of - /// struct definitions which are shared with C++, as it has identical - /// layout to our ns[C]String type. - /// - /// This struct will leak its data if dropped from rust. See the module - /// documentation for more information on this type. - #[repr(C)] - #[derive(Debug)] - pub struct $StringRepr { - data: *const $char_t, - length: u32, - dataflags: DataFlags, - classflags: ClassFlags, - } - - impl $StringRepr { - fn new(classflags: ClassFlags) -> $StringRepr { - static NUL: $char_t = 0; - $StringRepr { - data: &NUL, - length: 0, - dataflags: DataFlags::TERMINATED | DataFlags::LITERAL, - classflags: classflags, - } - } - } - - impl Deref for $StringRepr { - type Target = $AString; - fn deref(&self) -> &$AString { - unsafe { - mem::transmute(self) - } - } - } - - impl DerefMut for $StringRepr { - fn deref_mut(&mut self) -> &mut $AString { - unsafe { - mem::transmute(self) - } - } - } - - /// This type is the abstract type which is used for interacting with - /// strings in rust. Each string type can derefence to an instance of - /// this type, which provides the useful operations on strings. - /// - /// NOTE: Rust thinks this type has a size of 0, because the data - /// associated with it is not necessarially safe to move. It is not safe - /// to construct a nsAString yourself, unless it is received by - /// dereferencing one of these types. - /// - /// NOTE: The `[u8; 0]` member is zero sized, and only exists to prevent - /// the construction by code outside of this module. It is used instead - /// of a private `()` member because the `improper_ctypes` lint complains - /// about some ZST members in `extern "C"` function declarations. - #[repr(C)] - pub struct $AString { - _prohibit_constructor: [u8; 0], - } - - impl $AString { - /// Assign the value of `other` into self, overwriting any value - /// currently stored. Performs an optimized assignment when possible - /// if `other` is a `nsA[C]String`. - pub fn assign(&mut self, other: &T) { - unsafe { $assign(self, other.adapt().as_ptr()) }; - } - - /// Assign the value of `other` into self, overwriting any value - /// currently stored. Performs an optimized assignment when possible - /// if `other` is a `nsA[C]String`. - /// - /// Returns Ok(()) on success, and Err(()) if the allocation failed. - pub fn fallible_assign(&mut self, other: &T) -> Result<(), ()> { - if unsafe { $fallible_assign(self, other.adapt().as_ptr()) } { - Ok(()) - } else { - Err(()) - } - } - - /// Take the value of `other` and set `self`, overwriting any value - /// currently stored. The passed-in string will be truncated. - pub fn take_from(&mut self, other: &mut $AString) { - unsafe { $take_from(self, other) }; - } - - /// Take the value of `other` and set `self`, overwriting any value - /// currently stored. If this function fails, the source string will - /// be left untouched, otherwise it will be truncated. - /// - /// Returns Ok(()) on success, and Err(()) if the allocation failed. - pub fn fallible_take_from(&mut self, other: &mut $AString) -> Result<(), ()> { - if unsafe { $fallible_take_from(self, other) } { - Ok(()) - } else { - Err(()) - } - } - - /// Append the value of `other` into self. - pub fn append(&mut self, other: &T) { - unsafe { $append(self, other.adapt().as_ptr()) }; - } - - /// Append the value of `other` into self. - /// - /// Returns Ok(()) on success, and Err(()) if the allocation failed. - pub fn fallible_append(&mut self, other: &T) -> Result<(), ()> { - if unsafe { $fallible_append(self, other.adapt().as_ptr()) } { - Ok(()) - } else { - Err(()) - } - } - - /// Set the length of the string to the passed-in length, and expand - /// the backing capacity to match. This method is unsafe as it can - /// expose uninitialized memory when len is greater than the current - /// length of the string. - pub unsafe fn set_length(&mut self, len: u32) { - $set_length(self, len); - } - - /// Set the length of the string to the passed-in length, and expand - /// the backing capacity to match. This method is unsafe as it can - /// expose uninitialized memory when len is greater than the current - /// length of the string. - /// - /// Returns Ok(()) on success, and Err(()) if the allocation failed. - pub unsafe fn fallible_set_length(&mut self, len: u32) -> Result<(), ()> { - if $fallible_set_length(self, len) { - Ok(()) - } else { - Err(()) - } - } - - pub fn truncate(&mut self) { - unsafe { - self.set_length(0); - } - } - - /// Get a `&mut` reference to the backing data for this string. - /// This method will allocate and copy if the current backing buffer - /// is immutable or shared. - pub fn to_mut(&mut self) -> &mut [$char_t] { - unsafe { - let len = self.len(); - if len == 0 { - // Use an arbitrary non-null value as the pointer - slice::from_raw_parts_mut(0x1 as *mut $char_t, 0) - } else { - slice::from_raw_parts_mut($begin_writing(self), len) - } - } - } - - /// Get a `&mut` reference to the backing data for this string. - /// This method will allocate and copy if the current backing buffer - /// is immutable or shared. - /// - /// Returns `Ok(&mut [T])` on success, and `Err(())` if the - /// allocation failed. - pub fn fallible_to_mut(&mut self) -> Result<&mut [$char_t], ()> { - unsafe { - let len = self.len(); - if len == 0 { - // Use an arbitrary non-null value as the pointer - Ok(slice::from_raw_parts_mut(0x1 as *mut $char_t, 0)) - } else { - let ptr = $fallible_begin_writing(self); - if ptr.is_null() { - Err(()) - } else { - Ok(slice::from_raw_parts_mut(ptr, len)) - } - } - } - } - - } - - impl Deref for $AString { - type Target = [$char_t]; - fn deref(&self) -> &[$char_t] { - unsafe { - // All $AString values point to a struct prefix which is - // identical to $StringRepr, this we can transmute `self` - // into $StringRepr to get the reference to the underlying - // data. - let this: &$StringRepr = mem::transmute(self); - if this.data.is_null() { - debug_assert_eq!(this.length, 0); - // Use an arbitrary non-null value as the pointer - slice::from_raw_parts(0x1 as *const $char_t, 0) - } else { - slice::from_raw_parts(this.data, this.length as usize) - } - } - } - } - - impl AsRef<[$char_t]> for $AString { - fn as_ref(&self) -> &[$char_t] { - self - } - } - - impl cmp::PartialEq for $AString { - fn eq(&self, other: &$AString) -> bool { - &self[..] == &other[..] - } - } - - impl cmp::PartialEq<[$char_t]> for $AString { - fn eq(&self, other: &[$char_t]) -> bool { - &self[..] == other - } - } - - impl cmp::PartialEq<$String> for $AString { - fn eq(&self, other: &$String) -> bool { - self.eq(&**other) - } - } - - impl<'a> cmp::PartialEq<$Str<'a>> for $AString { - fn eq(&self, other: &$Str<'a>) -> bool { - self.eq(&**other) - } - } - - #[repr(C)] - pub struct $Str<'a> { - hdr: $StringRepr, - _marker: PhantomData<&'a [$char_t]>, - } - - impl $Str<'static> { - pub fn new() -> $Str<'static> { - $Str { - hdr: $StringRepr::new(ClassFlags::empty()), - _marker: PhantomData, - } - } - } - - impl<'a> Drop for $Str<'a> { - fn drop(&mut self) { - unsafe { - $drop(&mut **self); - } - } - } - - impl<'a> Deref for $Str<'a> { - type Target = $AString; - fn deref(&self) -> &$AString { - &self.hdr - } - } - - impl<'a> DerefMut for $Str<'a> { - fn deref_mut(&mut self) -> &mut $AString { - &mut self.hdr - } - } - - impl<'a> AsRef<[$char_t]> for $Str<'a> { - fn as_ref(&self) -> &[$char_t] { - &self - } - } - - impl<'a> From<&'a [$char_t]> for $Str<'a> { - fn from(s: &'a [$char_t]) -> $Str<'a> { - assert!(s.len() < (u32::MAX as usize)); - if s.is_empty() { - return $Str::new(); - } - $Str { - hdr: $StringRepr { - data: s.as_ptr(), - length: s.len() as u32, - dataflags: DataFlags::empty(), - classflags: ClassFlags::empty(), - }, - _marker: PhantomData, - } - } - } - - impl<'a> From<&'a Vec<$char_t>> for $Str<'a> { - fn from(s: &'a Vec<$char_t>) -> $Str<'a> { - $Str::from(&s[..]) - } - } - - impl<'a> From<&'a $AString> for $Str<'a> { - fn from(s: &'a $AString) -> $Str<'a> { - $Str::from(&s[..]) - } - } - - impl<'a> fmt::Write for $Str<'a> { - fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { - $AString::write_str(self, s) - } - } - - impl<'a> fmt::Display for $Str<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - <$AString as fmt::Display>::fmt(self, f) - } - } - - impl<'a> fmt::Debug for $Str<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - <$AString as fmt::Debug>::fmt(self, f) - } - } - - impl<'a> cmp::PartialEq for $Str<'a> { - fn eq(&self, other: &$Str<'a>) -> bool { - $AString::eq(self, other) - } - } - - impl<'a> cmp::PartialEq<[$char_t]> for $Str<'a> { - fn eq(&self, other: &[$char_t]) -> bool { - $AString::eq(self, other) - } - } - - impl<'a, 'b> cmp::PartialEq<&'b [$char_t]> for $Str<'a> { - fn eq(&self, other: &&'b [$char_t]) -> bool { - $AString::eq(self, *other) - } - } - - impl<'a> cmp::PartialEq for $Str<'a> { - fn eq(&self, other: &str) -> bool { - $AString::eq(self, other) - } - } - - impl<'a, 'b> cmp::PartialEq<&'b str> for $Str<'a> { - fn eq(&self, other: &&'b str) -> bool { - $AString::eq(self, *other) - } - } - - #[repr(C)] - pub struct $String { - hdr: $StringRepr, - } - - unsafe impl Send for $String {} - unsafe impl Sync for $String {} - - impl $String { - pub fn new() -> $String { - $String { - hdr: $StringRepr::new(ClassFlags::NULL_TERMINATED), - } - } - - /// Converts this String into a StringRepr, which will leak if the - /// repr is not passed to something that knows how to free it. - pub fn into_repr(mut self) -> $StringRepr { - mem::replace(&mut self.hdr, $StringRepr::new(ClassFlags::NULL_TERMINATED)) - } - } - - impl Drop for $String { - fn drop(&mut self) { - unsafe { - $drop(&mut **self); - } - } - } - - impl Deref for $String { - type Target = $AString; - fn deref(&self) -> &$AString { - &self.hdr - } - } - - impl DerefMut for $String { - fn deref_mut(&mut self) -> &mut $AString { - &mut self.hdr - } - } - - impl AsRef<[$char_t]> for $String { - fn as_ref(&self) -> &[$char_t] { - &self - } - } - - impl<'a> From<&'a [$char_t]> for $String { - fn from(s: &'a [$char_t]) -> $String { - let mut res = $String::new(); - res.assign(&$Str::from(&s[..])); - res - } - } - - impl<'a> From<&'a Vec<$char_t>> for $String { - fn from(s: &'a Vec<$char_t>) -> $String { - $String::from(&s[..]) - } - } - - impl<'a> From<&'a $AString> for $String { - fn from(s: &'a $AString) -> $String { - $String::from(&s[..]) - } - } - - impl From> for $String { - fn from(s: Box<[$char_t]>) -> $String { - s.to_vec().into() - } - } - - impl From> for $String { - fn from(mut s: Vec<$char_t>) -> $String { - assert!(s.len() < (u32::MAX as usize)); - if s.is_empty() { - return $String::new(); - } - - let length = s.len() as u32; - s.push(0); // null terminator - - // SAFETY NOTE: This method produces an data_flags::OWNED - // ns[C]String from a Box<[$char_t]>. this is only safe - // because in the Gecko tree, we use the same allocator for - // Rust code as for C++ code, meaning that our box can be - // legally freed with libc::free(). - let ptr = s.as_ptr(); - mem::forget(s); - unsafe { - Gecko_IncrementStringAdoptCount(ptr as *mut _); - } - $String { - hdr: $StringRepr { - data: ptr, - length: length, - dataflags: DataFlags::OWNED | DataFlags::TERMINATED, - classflags: ClassFlags::NULL_TERMINATED, - } - } - } - } - - impl fmt::Write for $String { - fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { - $AString::write_str(self, s) - } - } - - impl fmt::Display for $String { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - <$AString as fmt::Display>::fmt(self, f) - } - } - - impl fmt::Debug for $String { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - <$AString as fmt::Debug>::fmt(self, f) - } - } - - impl cmp::PartialEq for $String { - fn eq(&self, other: &$String) -> bool { - $AString::eq(self, other) - } - } - - impl cmp::PartialEq<[$char_t]> for $String { - fn eq(&self, other: &[$char_t]) -> bool { - $AString::eq(self, other) - } - } - - impl<'a> cmp::PartialEq<&'a [$char_t]> for $String { - fn eq(&self, other: &&'a [$char_t]) -> bool { - $AString::eq(self, *other) - } - } - - impl cmp::PartialEq for $String { - fn eq(&self, other: &str) -> bool { - $AString::eq(self, other) - } - } - - impl<'a> cmp::PartialEq<&'a str> for $String { - fn eq(&self, other: &&'a str) -> bool { - $AString::eq(self, *other) - } - } - - /// An adapter type to allow for passing both types which coerce to - /// &[$char_type], and &$AString to a function, while still performing - /// optimized operations when passed the $AString. - pub enum $StringAdapter<'a> { - Borrowed($Str<'a>), - Abstract(&'a $AString), - } - - impl<'a> $StringAdapter<'a> { - fn as_ptr(&self) -> *const $AString { - &**self - } - } - - impl<'a> Deref for $StringAdapter<'a> { - type Target = $AString; - - fn deref(&self) -> &$AString { - match *self { - $StringAdapter::Borrowed(ref s) => s, - $StringAdapter::Abstract(ref s) => s, - } - } - } - - /// This trait is implemented on types which are `ns[C]String`-like, in - /// that they can at very low cost be converted to a borrowed - /// `&nsA[C]String`. Unfortunately, the intermediate type - /// `ns[C]StringAdapter` is required as well due to types like `&[u8]` - /// needing to be (cheaply) wrapped in a `nsCString` on the stack to - /// create the `&nsACString`. - /// - /// This trait is used to DWIM when calling the methods on - /// `nsA[C]String`. - pub trait $StringLike { - fn adapt(&self) -> $StringAdapter; - } - - impl<'a, T: $StringLike + ?Sized> $StringLike for &'a T { - fn adapt(&self) -> $StringAdapter { - ::adapt(*self) - } - } - - impl<'a, T> $StringLike for borrow::Cow<'a, T> - where T: $StringLike + borrow::ToOwned + ?Sized { - fn adapt(&self) -> $StringAdapter { - ::adapt(self.as_ref()) - } - } - - impl $StringLike for $AString { - fn adapt(&self) -> $StringAdapter { - $StringAdapter::Abstract(self) - } - } - - impl<'a> $StringLike for $Str<'a> { - fn adapt(&self) -> $StringAdapter { - $StringAdapter::Abstract(self) - } - } - - impl $StringLike for $String { - fn adapt(&self) -> $StringAdapter { - $StringAdapter::Abstract(self) - } - } - - impl $StringLike for [$char_t] { - fn adapt(&self) -> $StringAdapter { - $StringAdapter::Borrowed($Str::from(self)) - } - } - - impl $StringLike for Vec<$char_t> { - fn adapt(&self) -> $StringAdapter { - $StringAdapter::Borrowed($Str::from(&self[..])) - } - } - - impl $StringLike for Box<[$char_t]> { - fn adapt(&self) -> $StringAdapter { - $StringAdapter::Borrowed($Str::from(&self[..])) - } - } - } -} - -/////////////////////////////////////////// -// Bindings for nsCString (u8 char type) // -/////////////////////////////////////////// - -define_string_types! { - char_t = u8; - - AString = nsACString; - String = nsCString; - Str = nsCStr; - - StringLike = nsCStringLike; - StringAdapter = nsCStringAdapter; - - StringRepr = nsCStringRepr; - - drop = Gecko_FinalizeCString; - assign = Gecko_AssignCString, Gecko_FallibleAssignCString; - take_from = Gecko_TakeFromCString, Gecko_FallibleTakeFromCString; - append = Gecko_AppendCString, Gecko_FallibleAppendCString; - set_length = Gecko_SetLengthCString, Gecko_FallibleSetLengthCString; - begin_writing = Gecko_BeginWritingCString, Gecko_FallibleBeginWritingCString; -} - -impl nsACString { - pub fn assign_utf16(&mut self, other: &T) { - self.truncate(); - self.append_utf16(other); - } - - pub fn fallible_assign_utf16(&mut self, other: &T) -> Result<(), ()> { - self.truncate(); - self.fallible_append_utf16(other) - } - - pub fn append_utf16(&mut self, other: &T) { - unsafe { - Gecko_AppendUTF16toCString(self, other.adapt().as_ptr()); - } - } - - pub fn fallible_append_utf16(&mut self, other: &T) -> Result<(), ()> { - if unsafe { Gecko_FallibleAppendUTF16toCString(self, other.adapt().as_ptr()) } { - Ok(()) - } else { - Err(()) - } - } - - pub unsafe fn as_str_unchecked(&self) -> &str { - str::from_utf8_unchecked(self) - } -} - -impl<'a> From<&'a str> for nsCStr<'a> { - fn from(s: &'a str) -> nsCStr<'a> { - s.as_bytes().into() - } -} - -impl<'a> From<&'a String> for nsCStr<'a> { - fn from(s: &'a String) -> nsCStr<'a> { - nsCStr::from(&s[..]) - } -} - -impl<'a> From<&'a str> for nsCString { - fn from(s: &'a str) -> nsCString { - s.as_bytes().into() - } -} - -impl<'a> From<&'a String> for nsCString { - fn from(s: &'a String) -> nsCString { - nsCString::from(&s[..]) - } -} - -impl From> for nsCString { - fn from(s: Box) -> nsCString { - s.into_string().into() - } -} - -impl From for nsCString { - fn from(s: String) -> nsCString { - s.into_bytes().into() - } -} - -// Support for the write!() macro for appending to nsACStrings -impl fmt::Write for nsACString { - fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { - self.append(s); - Ok(()) - } -} - -impl fmt::Display for nsACString { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - fmt::Display::fmt(&String::from_utf8_lossy(&self[..]), f) - } -} - -impl fmt::Debug for nsACString { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - fmt::Debug::fmt(&String::from_utf8_lossy(&self[..]), f) - } -} - -impl cmp::PartialEq for nsACString { - fn eq(&self, other: &str) -> bool { - &self[..] == other.as_bytes() - } -} - -impl nsCStringLike for str { - fn adapt(&self) -> nsCStringAdapter { - nsCStringAdapter::Borrowed(nsCStr::from(self)) - } -} - -impl nsCStringLike for String { - fn adapt(&self) -> nsCStringAdapter { - nsCStringAdapter::Borrowed(nsCStr::from(&self[..])) - } -} - -impl nsCStringLike for Box { - fn adapt(&self) -> nsCStringAdapter { - nsCStringAdapter::Borrowed(nsCStr::from(&self[..])) - } -} - -/////////////////////////////////////////// -// Bindings for nsString (u16 char type) // -/////////////////////////////////////////// - -define_string_types! { - char_t = u16; - - AString = nsAString; - String = nsString; - Str = nsStr; - - StringLike = nsStringLike; - StringAdapter = nsStringAdapter; - - StringRepr = nsStringRepr; - - drop = Gecko_FinalizeString; - assign = Gecko_AssignString, Gecko_FallibleAssignString; - take_from = Gecko_TakeFromString, Gecko_FallibleTakeFromString; - append = Gecko_AppendString, Gecko_FallibleAppendString; - set_length = Gecko_SetLengthString, Gecko_FallibleSetLengthString; - begin_writing = Gecko_BeginWritingString, Gecko_FallibleBeginWritingString; -} - -impl nsAString { - pub fn assign_utf8(&mut self, other: &T) { - self.truncate(); - self.append_utf8(other); - } - - pub fn fallible_assign_utf8(&mut self, other: &T) -> Result<(), ()> { - self.truncate(); - self.fallible_append_utf8(other) - } - - pub fn append_utf8(&mut self, other: &T) { - unsafe { - Gecko_AppendUTF8toString(self, other.adapt().as_ptr()); - } - } - - pub fn fallible_append_utf8(&mut self, other: &T) -> Result<(), ()> { - if unsafe { Gecko_FallibleAppendUTF8toString(self, other.adapt().as_ptr()) } { - Ok(()) - } else { - Err(()) - } - } -} - -// NOTE: The From impl for a string slice for nsString produces a <'static> -// lifetime, as it allocates. -impl<'a> From<&'a str> for nsString { - fn from(s: &'a str) -> nsString { - s.encode_utf16().collect::>().into() - } -} - -impl<'a> From<&'a String> for nsString { - fn from(s: &'a String) -> nsString { - nsString::from(&s[..]) - } -} - -// Support for the write!() macro for writing to nsStrings -impl fmt::Write for nsAString { - fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { - // Directly invoke gecko's routines for appending utf8 strings to - // nsAString values, to avoid as much overhead as possible - self.append_utf8(s); - Ok(()) - } -} - -impl fmt::Display for nsAString { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - fmt::Display::fmt(&String::from_utf16_lossy(&self[..]), f) - } -} - -impl fmt::Debug for nsAString { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - fmt::Debug::fmt(&String::from_utf16_lossy(&self[..]), f) - } -} - -impl cmp::PartialEq for nsAString { - fn eq(&self, other: &str) -> bool { - other.encode_utf16().eq(self.iter().cloned()) - } -} - -#[cfg(not(feature = "gecko_debug"))] -#[allow(non_snake_case)] -unsafe fn Gecko_IncrementStringAdoptCount(_: *mut c_void) {} - -extern "C" { - #[cfg(feature = "gecko_debug")] - fn Gecko_IncrementStringAdoptCount(data: *mut c_void); - - // Gecko implementation in nsSubstring.cpp - fn Gecko_FinalizeCString(this: *mut nsACString); - - fn Gecko_AssignCString(this: *mut nsACString, other: *const nsACString); - fn Gecko_TakeFromCString(this: *mut nsACString, other: *mut nsACString); - fn Gecko_AppendCString(this: *mut nsACString, other: *const nsACString); - fn Gecko_SetLengthCString(this: *mut nsACString, length: u32); - fn Gecko_BeginWritingCString(this: *mut nsACString) -> *mut u8; - fn Gecko_FallibleAssignCString(this: *mut nsACString, other: *const nsACString) -> bool; - fn Gecko_FallibleTakeFromCString(this: *mut nsACString, other: *mut nsACString) -> bool; - fn Gecko_FallibleAppendCString(this: *mut nsACString, other: *const nsACString) -> bool; - fn Gecko_FallibleSetLengthCString(this: *mut nsACString, length: u32) -> bool; - fn Gecko_FallibleBeginWritingCString(this: *mut nsACString) -> *mut u8; - - fn Gecko_FinalizeString(this: *mut nsAString); - - fn Gecko_AssignString(this: *mut nsAString, other: *const nsAString); - fn Gecko_TakeFromString(this: *mut nsAString, other: *mut nsAString); - fn Gecko_AppendString(this: *mut nsAString, other: *const nsAString); - fn Gecko_SetLengthString(this: *mut nsAString, length: u32); - fn Gecko_BeginWritingString(this: *mut nsAString) -> *mut u16; - fn Gecko_FallibleAssignString(this: *mut nsAString, other: *const nsAString) -> bool; - fn Gecko_FallibleTakeFromString(this: *mut nsAString, other: *mut nsAString) -> bool; - fn Gecko_FallibleAppendString(this: *mut nsAString, other: *const nsAString) -> bool; - fn Gecko_FallibleSetLengthString(this: *mut nsAString, length: u32) -> bool; - fn Gecko_FallibleBeginWritingString(this: *mut nsAString) -> *mut u16; - - // Gecko implementation in nsReadableUtils.cpp - fn Gecko_AppendUTF16toCString(this: *mut nsACString, other: *const nsAString); - fn Gecko_AppendUTF8toString(this: *mut nsAString, other: *const nsACString); - fn Gecko_FallibleAppendUTF16toCString(this: *mut nsACString, other: *const nsAString) -> bool; - fn Gecko_FallibleAppendUTF8toString(this: *mut nsAString, other: *const nsACString) -> bool; -} - -////////////////////////////////////// -// Repr Validation Helper Functions // -////////////////////////////////////// - -pub mod test_helpers { - //! This module only exists to help with ensuring that the layout of the - //! structs inside of rust and C++ are identical. - //! - //! It is public to ensure that these testing functions are avaliable to - //! gtest code. - - use std::mem; - use super::{ClassFlags, DataFlags}; - use super::{nsCStr, nsCString, nsCStringRepr}; - use super::{nsStr, nsString, nsStringRepr}; - - /// Generates an #[no_mangle] extern "C" function which returns the size and - /// alignment of the given type with the given name. - macro_rules! size_align_check { - ($T:ty, $fname:ident) => { - #[no_mangle] - #[allow(non_snake_case)] - pub extern fn $fname(size: *mut usize, align: *mut usize) { - unsafe { - *size = mem::size_of::<$T>(); - *align = mem::align_of::<$T>(); - } - } - }; - ($T:ty, $U:ty, $V:ty, $fname:ident) => { - #[no_mangle] - #[allow(non_snake_case)] - pub extern fn $fname(size: *mut usize, align: *mut usize) { - unsafe { - *size = mem::size_of::<$T>(); - *align = mem::align_of::<$T>(); - - assert_eq!(*size, mem::size_of::<$U>()); - assert_eq!(*align, mem::align_of::<$U>()); - assert_eq!(*size, mem::size_of::<$V>()); - assert_eq!(*align, mem::align_of::<$V>()); - } - } - } - } - - size_align_check!(nsStringRepr, nsString, nsStr<'static>, - Rust_Test_ReprSizeAlign_nsString); - size_align_check!(nsCStringRepr, nsCString, nsCStr<'static>, - Rust_Test_ReprSizeAlign_nsCString); - - /// Generates a $[no_mangle] extern "C" function which returns the size, - /// alignment and offset in the parent struct of a given member, with the - /// given name. - /// - /// This method can trigger Undefined Behavior if the accessing the member - /// $member on a given type would use that type's `Deref` implementation. - macro_rules! member_check { - ($T:ty, $member:ident, $method:ident) => { - #[no_mangle] - #[allow(non_snake_case)] - pub extern fn $method(size: *mut usize, - align: *mut usize, - offset: *mut usize) { - unsafe { - // Create a temporary value of type T to get offsets, sizes - // and aligns off of - let tmp: $T = mem::zeroed(); - *size = mem::size_of_val(&tmp.$member); - *align = mem::align_of_val(&tmp.$member); - *offset = - (&tmp.$member as *const _ as usize) - - (&tmp as *const _ as usize); - mem::forget(tmp); - } - } - }; - ($T:ty, $U:ty, $V:ty, $member:ident, $method:ident) => { - #[no_mangle] - #[allow(non_snake_case)] - pub extern fn $method(size: *mut usize, - align: *mut usize, - offset: *mut usize) { - unsafe { - // Create a temporary value of type T to get offsets, sizes - // and alignments from. - let tmp: $T = mem::zeroed(); - *size = mem::size_of_val(&tmp.$member); - *align = mem::align_of_val(&tmp.$member); - *offset = - (&tmp.$member as *const _ as usize) - - (&tmp as *const _ as usize); - mem::forget(tmp); - - let tmp: $U = mem::zeroed(); - assert_eq!(*size, mem::size_of_val(&tmp.hdr.$member)); - assert_eq!(*align, mem::align_of_val(&tmp.hdr.$member)); - assert_eq!(*offset, - (&tmp.hdr.$member as *const _ as usize) - - (&tmp as *const _ as usize)); - mem::forget(tmp); - - let tmp: $V = mem::zeroed(); - assert_eq!(*size, mem::size_of_val(&tmp.hdr.$member)); - assert_eq!(*align, mem::align_of_val(&tmp.hdr.$member)); - assert_eq!(*offset, - (&tmp.hdr.$member as *const _ as usize) - - (&tmp as *const _ as usize)); - mem::forget(tmp); - } - } - } - } - - member_check!(nsStringRepr, nsString, nsStr<'static>, - data, Rust_Test_Member_nsString_mData); - member_check!(nsStringRepr, nsString, nsStr<'static>, - length, Rust_Test_Member_nsString_mLength); - member_check!(nsStringRepr, nsString, nsStr<'static>, - dataflags, Rust_Test_Member_nsString_mDataFlags); - member_check!(nsStringRepr, nsString, nsStr<'static>, - classflags, Rust_Test_Member_nsString_mClassFlags); - member_check!(nsCStringRepr, nsCString, nsCStr<'static>, - data, Rust_Test_Member_nsCString_mData); - member_check!(nsCStringRepr, nsCString, nsCStr<'static>, - length, Rust_Test_Member_nsCString_mLength); - member_check!(nsCStringRepr, nsCString, nsCStr<'static>, - dataflags, Rust_Test_Member_nsCString_mDataFlags); - member_check!(nsCStringRepr, nsCString, nsCStr<'static>, - classflags, Rust_Test_Member_nsCString_mClassFlags); - - #[no_mangle] - #[allow(non_snake_case)] - pub extern fn 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) { - unsafe { - *f_terminated = DataFlags::TERMINATED.bits(); - *f_voided = DataFlags::VOIDED.bits(); - *f_refcounted = DataFlags::REFCOUNTED.bits(); - *f_owned = DataFlags::OWNED.bits(); - *f_inline = DataFlags::INLINE.bits(); - *f_literal = DataFlags::LITERAL.bits(); - *f_class_inline = ClassFlags::INLINE.bits(); - *f_class_null_terminated = ClassFlags::NULL_TERMINATED.bits(); - } - } -}