diff --git a/Cargo.lock b/Cargo.lock index 99c94f92ee7..040dd59c0ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2045,6 +2045,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "nsstring_vendor" version = "0.1.0" +dependencies = [ + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "num-integer" diff --git a/components/style/gecko/values.rs b/components/style/gecko/values.rs index ac9a37d4395..09a796c5980 100644 --- a/components/style/gecko/values.rs +++ b/components/style/gecko/values.rs @@ -14,7 +14,7 @@ use gecko_bindings::structs::{CounterStylePtr, nsStyleCoord}; use gecko_bindings::structs::{StyleGridTrackBreadth, StyleShapeRadius}; use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue}; use media_queries::Device; -use nsstring::{nsACString, nsCString}; +use nsstring::{nsACString, nsCStr}; use std::cmp::max; use values::{Auto, Either, ExtremumLength, None_, Normal}; use values::computed::{Angle, Length, LengthOrPercentage, LengthOrPercentageOrAuto}; @@ -465,7 +465,7 @@ impl CounterStyleOrNone { }, CounterStyleOrNone::Symbols(symbols_type, symbols) => { let symbols: Vec<_> = symbols.0.iter().map(|symbol| match *symbol { - Symbol::String(ref s) => nsCString::from(s), + Symbol::String(ref s) => nsCStr::from(s), Symbol::Ident(_) => unreachable!("Should not have identifier in symbols()"), }).collect(); let symbols: Vec<_> = symbols.iter() diff --git a/components/style/gecko_bindings/nsstring_vendor/Cargo.toml b/components/style/gecko_bindings/nsstring_vendor/Cargo.toml index c1294f34ea8..5aca14f7c2e 100644 --- a/components/style/gecko_bindings/nsstring_vendor/Cargo.toml +++ b/components/style/gecko_bindings/nsstring_vendor/Cargo.toml @@ -9,6 +9,7 @@ description = "Rust bindings to xpcom string types" # Revendoring nsstring from m-c into Servo [dependencies] +bitflags = "0.8" [features] gecko_debug = [] diff --git a/components/style/gecko_bindings/nsstring_vendor/src/lib.rs b/components/style/gecko_bindings/nsstring_vendor/src/lib.rs index 385fe5f24da..bff11c59ec1 100644 --- a/components/style/gecko_bindings/nsstring_vendor/src/lib.rs +++ b/components/style/gecko_bindings/nsstring_vendor/src/lib.rs @@ -9,12 +9,18 @@ //! 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<'a>` (`ns[C]String` in C++) for string struct members, and -//! as an intermediate between rust string data structures (such as `String`, -//! `Vec`, `&str`, and `&[u16]`) and `&{mut,} nsA[C]String` (using -//! `ns[C]String::from(value)`). These conversions, when possible, will not -//! perform any allocations. When using this type in structs shared with C++, -//! the correct lifetime argument is usually `'static`. +//! 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 `nsFixed[C]String` or `ns_auto_[c]string!` for dynamic stack allocated //! strings which are expected to hold short string values. @@ -52,7 +58,7 @@ //! with the methods `.append`, `.append_utf{8,16}`, and with the `write!` //! macro, and can be assigned to with `.assign`. //! -//! ## `ns[C]String<'a>` +//! ## `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 @@ -61,20 +67,36 @@ //! storage. When modified this type may re-allocate in order to ensure that it //! does not mutate its backing storage. //! -//! `ns[C]String`s can be constructed either with `ns[C]String::new()`, which -//! creates an empty `ns[C]String<'static>`, or through one of the provided -//! `From` implementations. Both string types may be constructed `From<&'a -//! str>`, with `nsCString` having a `'a` lifetime, as the storage is shared -//! with the `str`, while `nsString` has a `'static` lifetime, as its storage -//! has to be transcoded. +//! `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. This struct may also be included in `#[repr(C)]` -//! structs shared with C++. +//! 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++. //! //! ## `nsFixed[C]String<'a>` //! @@ -109,7 +131,7 @@ //! ## `ns[C]StringRepr` //! //! This crate also provides the type `ns[C]StringRepr` which acts conceptually -//! similar to an `ns[C]String<'static>`, however, it does not have a `Drop` +//! 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 @@ -119,11 +141,13 @@ #![allow(non_camel_case_types)] #![deny(warnings)] +#[macro_use] +extern crate bitflags; + use std::ops::{Deref, DerefMut}; use std::marker::PhantomData; use std::borrow; use std::slice; -use std::ptr; use std::mem; use std::fmt; use std::cmp; @@ -135,13 +159,36 @@ use std::os::raw::c_void; // Internal Implemenation Flags // ////////////////////////////////// -const F_NONE: u32 = 0; // no 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 flags DataFlags : u16 { + const TERMINATED = 1 << 0, // IsTerminated returns true + const VOIDED = 1 << 1, // IsVoid returns true + const SHARED = 1 << 2, // mData points to a heap-allocated, shared buffer + const OWNED = 1 << 3, // mData points to a heap-allocated, raw buffer + const FIXED = 1 << 4, // mData points to a fixed-size writable, dependent buffer + const LITERAL = 1 << 5, // mData points to a string literal; TERMINATED will also be set + } + } +} -// data flags are in the lower 16-bits -const F_OWNED: u32 = 1 << 3; // mData points to a heap-allocated, raw buffer +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 flags ClassFlags : u16 { + const FIXED = 1 << 0, // |this| is of type nsTFixedString + const NULL_TERMINATED = 1 << 1, // |this| requires its buffer is null-terminated + } + } +} -// class flags are in the upper 16-bits -const F_CLASS_FIXED: u32 = 1 << 16; // indicates that |this| is of type nsTFixedString +use data_flags::DataFlags; +use class_flags::ClassFlags; //////////////////////////////////// // Generic String Bindings Macros // @@ -153,6 +200,7 @@ macro_rules! define_string_types { AString = $AString: ident; String = $String: ident; + Str = $Str: ident; FixedString = $FixedString: ident; StringLike = $StringLike: ident; @@ -162,8 +210,10 @@ macro_rules! define_string_types { 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 @@ -180,7 +230,20 @@ macro_rules! define_string_types { pub struct $StringRepr { data: *const $char_t, length: u32, - flags: u32, + dataflags: DataFlags, + classflags: ClassFlags, + } + + impl $StringRepr { + fn new(classflags: ClassFlags) -> $StringRepr { + static NUL: $char_t = 0; + $StringRepr { + data: &NUL, + length: 0, + dataflags: data_flags::TERMINATED | data_flags::LITERAL, + classflags: classflags, + } + } } impl Deref for $StringRepr { @@ -239,6 +302,25 @@ macro_rules! define_string_types { } } + /// 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()) }; @@ -282,6 +364,45 @@ macro_rules! define_string_types { 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 { @@ -322,8 +443,14 @@ macro_rules! define_string_types { } } - impl<'a> cmp::PartialEq<$String<'a>> for $AString { - fn eq(&self, other: &$String<'a>) -> bool { + 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) } } @@ -335,25 +462,21 @@ macro_rules! define_string_types { } #[repr(C)] - pub struct $String<'a> { + pub struct $Str<'a> { hdr: $StringRepr, _marker: PhantomData<&'a [$char_t]>, } - impl $String<'static> { - pub fn new() -> $String<'static> { - $String { - hdr: $StringRepr { - data: ptr::null(), - length: 0, - flags: F_NONE, - }, + impl $Str<'static> { + pub fn new() -> $Str<'static> { + $Str { + hdr: $StringRepr::new(ClassFlags::empty()), _marker: PhantomData, } } } - impl<'a> Drop for $String<'a> { + impl<'a> Drop for $Str<'a> { fn drop(&mut self) { unsafe { $drop(&mut **self); @@ -361,64 +484,184 @@ macro_rules! define_string_types { } } - impl<'a> Deref for $String<'a> { + impl<'a> Deref for $Str<'a> { type Target = $AString; fn deref(&self) -> &$AString { &self.hdr } } - impl<'a> DerefMut for $String<'a> { + impl<'a> DerefMut for $Str<'a> { fn deref_mut(&mut self) -> &mut $AString { &mut self.hdr } } - impl<'a> AsRef<[$char_t]> for $String<'a> { + impl<'a> AsRef<[$char_t]> for $Str<'a> { fn as_ref(&self) -> &[$char_t] { &self } } - impl<'a> From<&'a String> for $String<'a> { - fn from(s: &'a String) -> $String<'a> { - $String::from(&s[..]) - } - } - - impl<'a> From<&'a Vec<$char_t>> for $String<'a> { - fn from(s: &'a Vec<$char_t>) -> $String<'a> { - $String::from(&s[..]) - } - } - - impl<'a> From<&'a [$char_t]> for $String<'a> { - fn from(s: &'a [$char_t]) -> $String<'a> { + impl<'a> From<&'a [$char_t]> for $Str<'a> { + fn from(s: &'a [$char_t]) -> $Str<'a> { assert!(s.len() < (u32::MAX as usize)); - $String { + if s.is_empty() { + return $Str::new(); + } + $Str { hdr: $StringRepr { - data: if s.is_empty() { ptr::null() } else { s.as_ptr() }, + data: s.as_ptr(), length: s.len() as u32, - flags: F_NONE, + dataflags: DataFlags::empty(), + classflags: ClassFlags::empty(), }, _marker: PhantomData, } } } - impl From> for $String<'static> { - fn from(s: Box<[$char_t]>) -> $String<'static> { + 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, + } + + impl $String { + pub fn new() -> $String { + $String { + hdr: $StringRepr::new(class_flags::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(); } - // SAFETY NOTE: This method produces an F_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 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 { @@ -428,71 +671,57 @@ macro_rules! define_string_types { hdr: $StringRepr { data: ptr, length: length, - flags: F_OWNED, - }, - _marker: PhantomData, + dataflags: data_flags::OWNED | data_flags::TERMINATED, + classflags: class_flags::NULL_TERMINATED, + } } } } - impl From> for $String<'static> { - fn from(s: Vec<$char_t>) -> $String<'static> { - s.into_boxed_slice().into() - } - } - - impl<'a> From<&'a $AString> for $String<'static> { - fn from(s: &'a $AString) -> $String<'static> { - let mut string = $String::new(); - string.assign(s); - string - } - } - - impl<'a> fmt::Write for $String<'a> { + impl fmt::Write for $String { fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { $AString::write_str(self, s) } } - impl<'a> fmt::Display for $String<'a> { + impl fmt::Display for $String { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { <$AString as fmt::Display>::fmt(self, f) } } - impl<'a> fmt::Debug for $String<'a> { + impl fmt::Debug for $String { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { <$AString as fmt::Debug>::fmt(self, f) } } - impl<'a> cmp::PartialEq for $String<'a> { - fn eq(&self, other: &$String<'a>) -> bool { + impl cmp::PartialEq for $String { + fn eq(&self, other: &$String) -> bool { $AString::eq(self, other) } } - impl<'a> cmp::PartialEq<[$char_t]> for $String<'a> { + impl cmp::PartialEq<[$char_t]> for $String { fn eq(&self, other: &[$char_t]) -> bool { $AString::eq(self, other) } } - impl<'a, 'b> cmp::PartialEq<&'b [$char_t]> for $String<'a> { - fn eq(&self, other: &&'b [$char_t]) -> bool { + impl<'a> cmp::PartialEq<&'a [$char_t]> for $String { + fn eq(&self, other: &&'a [$char_t]) -> bool { $AString::eq(self, *other) } } - impl<'a> cmp::PartialEq for $String<'a> { + impl cmp::PartialEq for $String { fn eq(&self, other: &str) -> bool { $AString::eq(self, other) } } - impl<'a, 'b> cmp::PartialEq<&'b str> for $String<'a> { - fn eq(&self, other: &&'b str) -> bool { + impl<'a> cmp::PartialEq<&'a str> for $String { + fn eq(&self, other: &&'a str) -> bool { $AString::eq(self, *other) } } @@ -502,7 +731,7 @@ macro_rules! define_string_types { /// buffer, rather than using heap allocations. #[repr(C)] pub struct $FixedString<'a> { - base: $String<'a>, + base: $String, capacity: u32, buffer: *mut $char_t, _marker: PhantomData<&'a mut [$char_t]>, @@ -515,12 +744,7 @@ macro_rules! define_string_types { let buf_ptr = buf.as_mut_ptr(); $FixedString { base: $String { - hdr: $StringRepr { - data: ptr::null(), - length: 0, - flags: F_CLASS_FIXED, - }, - _marker: PhantomData, + hdr: $StringRepr::new(class_flags::FIXED | class_flags::NULL_TERMINATED), }, capacity: len as u32, buffer: buf_ptr, @@ -600,7 +824,7 @@ macro_rules! define_string_types { /// &[$char_type], and &$AString to a function, while still performing /// optimized operations when passed the $AString. pub enum $StringAdapter<'a> { - Borrowed($String<'a>), + Borrowed($Str<'a>), Abstract(&'a $AString), } @@ -653,7 +877,13 @@ macro_rules! define_string_types { } } - impl<'a> $StringLike for $String<'a> { + impl<'a> $StringLike for $Str<'a> { + fn adapt(&self) -> $StringAdapter { + $StringAdapter::Abstract(self) + } + } + + impl $StringLike for $String { fn adapt(&self) -> $StringAdapter { $StringAdapter::Abstract(self) } @@ -667,19 +897,19 @@ macro_rules! define_string_types { impl $StringLike for [$char_t] { fn adapt(&self) -> $StringAdapter { - $StringAdapter::Borrowed($String::from(self)) + $StringAdapter::Borrowed($Str::from(self)) } } impl $StringLike for Vec<$char_t> { fn adapt(&self) -> $StringAdapter { - $StringAdapter::Borrowed($String::from(&self[..])) + $StringAdapter::Borrowed($Str::from(&self[..])) } } impl $StringLike for Box<[$char_t]> { fn adapt(&self) -> $StringAdapter { - $StringAdapter::Borrowed($String::from(&self[..])) + $StringAdapter::Borrowed($Str::from(&self[..])) } } } @@ -694,6 +924,7 @@ define_string_types! { AString = nsACString; String = nsCString; + Str = nsCStr; FixedString = nsFixedCString; StringLike = nsCStringLike; @@ -703,8 +934,10 @@ define_string_types! { 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 { @@ -737,20 +970,38 @@ impl nsACString { } } -impl<'a> From<&'a str> for nsCString<'a> { - fn from(s: &'a str) -> nsCString<'a> { +impl<'a> From<&'a str> for nsCStr<'a> { + fn from(s: &'a str) -> nsCStr<'a> { s.as_bytes().into() } } -impl From> for nsCString<'static> { - fn from(s: Box) -> nsCString<'static> { +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<'static> { - fn from(s: String) -> nsCString<'static> { +impl From for nsCString { + fn from(s: String) -> nsCString { s.into_bytes().into() } } @@ -783,19 +1034,19 @@ impl cmp::PartialEq for nsACString { impl nsCStringLike for str { fn adapt(&self) -> nsCStringAdapter { - nsCStringAdapter::Borrowed(nsCString::from(self)) + nsCStringAdapter::Borrowed(nsCStr::from(self)) } } impl nsCStringLike for String { fn adapt(&self) -> nsCStringAdapter { - nsCStringAdapter::Borrowed(nsCString::from(&self[..])) + nsCStringAdapter::Borrowed(nsCStr::from(&self[..])) } } impl nsCStringLike for Box { fn adapt(&self) -> nsCStringAdapter { - nsCStringAdapter::Borrowed(nsCString::from(&self[..])) + nsCStringAdapter::Borrowed(nsCStr::from(&self[..])) } } @@ -816,6 +1067,7 @@ define_string_types! { AString = nsAString; String = nsString; + Str = nsStr; FixedString = nsFixedString; StringLike = nsStringLike; @@ -825,8 +1077,10 @@ define_string_types! { 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 { @@ -857,12 +1111,18 @@ impl nsAString { // NOTE: The From impl for a string slice for nsString produces a <'static> // lifetime, as it allocates. -impl<'a> From<&'a str> for nsString<'static> { - fn from(s: &'a str) -> nsString<'static> { +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> { @@ -911,20 +1171,28 @@ extern "C" { 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); diff --git a/components/style/gecko_string_cache/mod.rs b/components/style/gecko_string_cache/mod.rs index 0c75e0c43ca..20121d5f548 100644 --- a/components/style/gecko_string_cache/mod.rs +++ b/components/style/gecko_string_cache/mod.rs @@ -11,7 +11,7 @@ use gecko_bindings::bindings::Gecko_Atomize; use gecko_bindings::bindings::Gecko_Atomize16; use gecko_bindings::bindings::Gecko_ReleaseAtom; use gecko_bindings::structs::{nsIAtom, nsIAtom_AtomKind}; -use nsstring::{nsAString, nsString}; +use nsstring::{nsAString, nsStr}; use precomputed_hash::PrecomputedHash; use std::ascii::AsciiExt; use std::borrow::{Cow, Borrow}; @@ -346,7 +346,7 @@ impl<'a> From<&'a str> for Atom { impl<'a> From<&'a [u16]> for Atom { #[inline] fn from(slice: &[u16]) -> Atom { - Atom::from(&*nsString::from(slice)) + Atom::from(&*nsStr::from(slice)) } } diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index c8116a975ec..fece19bb10e 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -4086,13 +4086,13 @@ fn static_assert() { pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T, device: &Device) { use gecko_bindings::bindings::Gecko_SetCounterStyleToString; - use nsstring::{nsACString, nsCString}; + use nsstring::{nsACString, nsCStr}; use self::longhands::list_style_type::computed_value::T; match v { T::CounterStyle(s) => s.to_gecko_value(&mut self.gecko.mCounterStyle, device), T::String(s) => unsafe { Gecko_SetCounterStyleToString(&mut self.gecko.mCounterStyle, - &nsCString::from(s) as &nsACString) + &nsCStr::from(&s) as &nsACString) } } } @@ -4679,9 +4679,8 @@ fn static_assert() { <%call expr="impl_coord_copy('word_spacing', 'mWordSpacing')"> fn clear_text_emphasis_style_if_string(&mut self) { - use nsstring::nsString; if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 { - self.gecko.mTextEmphasisStyleString.assign(&nsString::new()); + self.gecko.mTextEmphasisStyleString.truncate(); self.gecko.mTextEmphasisStyle = structs::NS_STYLE_TEXT_EMPHASIS_STYLE_NONE as u8; } } @@ -4797,10 +4796,9 @@ fn static_assert() { fn clear_overflow_sides_if_string(&mut self) { use gecko_bindings::structs::nsStyleTextOverflowSide; - use nsstring::nsString; fn clear_if_string(side: &mut nsStyleTextOverflowSide) { if side.mType == structs::NS_STYLE_TEXT_OVERFLOW_STRING as u8 { - side.mString.assign(&nsString::new()); + side.mString.truncate(); side.mType = structs::NS_STYLE_TEXT_OVERFLOW_CLIP as u8; } } diff --git a/components/style/stylesheets/document_rule.rs b/components/style/stylesheets/document_rule.rs index b0e36d52c73..e85d0c31496 100644 --- a/components/style/stylesheets/document_rule.rs +++ b/components/style/stylesheets/document_rule.rs @@ -138,7 +138,7 @@ impl UrlMatchingFunction { pub fn evaluate(&self, device: &Device) -> bool { use gecko_bindings::bindings::Gecko_DocumentRule_UseForPresentation; use gecko_bindings::structs::URLMatchingFunction as GeckoUrlMatchingFunction; - use nsstring::nsCString; + use nsstring::nsCStr; let func = match *self { UrlMatchingFunction::Url(_) => GeckoUrlMatchingFunction::eURL, @@ -147,7 +147,7 @@ impl UrlMatchingFunction { UrlMatchingFunction::RegExp(_) => GeckoUrlMatchingFunction::eRegExp, }; - let pattern = nsCString::from(match *self { + let pattern = nsCStr::from(match *self { UrlMatchingFunction::Url(ref url) => url.as_str(), UrlMatchingFunction::UrlPrefix(ref pat) | UrlMatchingFunction::Domain(ref pat) |