Improve inlining of Dynamic methods.

This commit is contained in:
Stephen Chung 2020-07-22 13:05:24 +08:00
parent 839738b97e
commit 187824e684
3 changed files with 240 additions and 109 deletions

View File

@ -203,6 +203,7 @@ impl Dynamic {
} }
/// Map the name of a standard type into a friendly form. /// Map the name of a standard type into a friendly form.
#[inline]
pub(crate) fn map_std_type_name(name: &str) -> &str { pub(crate) fn map_std_type_name(name: &str) -> &str {
if name == type_name::<String>() { if name == type_name::<String>() {
"string" "string"
@ -340,30 +341,47 @@ impl Dynamic {
/// assert_eq!(new_result.type_name(), "string"); /// assert_eq!(new_result.type_name(), "string");
/// assert_eq!(new_result.to_string(), "hello"); /// assert_eq!(new_result.to_string(), "hello");
/// ``` /// ```
#[inline(always)]
pub fn from<T: Variant + Clone>(value: T) -> Self { pub fn from<T: Variant + Clone>(value: T) -> Self {
if let Some(result) = <dyn Any>::downcast_ref::<()>(&value) { let type_id = TypeId::of::<T>();
return result.clone().into();
} else if let Some(result) = <dyn Any>::downcast_ref::<bool>(&value) {
return result.clone().into();
} else if let Some(result) = <dyn Any>::downcast_ref::<INT>(&value) {
return result.clone().into();
} else if let Some(result) = <dyn Any>::downcast_ref::<char>(&value) {
return result.clone().into();
} else if let Some(result) = <dyn Any>::downcast_ref::<ImmutableString>(&value) {
return result.clone().into();
}
if type_id == TypeId::of::<INT>() {
return <dyn Any>::downcast_ref::<INT>(&value)
.unwrap()
.clone()
.into();
}
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
if let Some(result) = <dyn Any>::downcast_ref::<FLOAT>(&value) { if type_id == TypeId::of::<FLOAT>() {
return result.clone().into(); return <dyn Any>::downcast_ref::<FLOAT>(&value)
.unwrap()
.clone()
.into();
}
if type_id == TypeId::of::<bool>() {
return <dyn Any>::downcast_ref::<bool>(&value)
.unwrap()
.clone()
.into();
}
if type_id == TypeId::of::<char>() {
return <dyn Any>::downcast_ref::<char>(&value)
.unwrap()
.clone()
.into();
}
if type_id == TypeId::of::<ImmutableString>() {
return <dyn Any>::downcast_ref::<ImmutableString>(&value)
.unwrap()
.clone()
.into();
}
if type_id == TypeId::of::<()>() {
return ().into();
} }
let mut boxed = Box::new(value); let mut boxed = Box::new(value);
boxed = match unsafe_cast_box::<_, Dynamic>(boxed) {
Ok(d) => return *d,
Err(val) => val,
};
boxed = match unsafe_cast_box::<_, String>(boxed) { boxed = match unsafe_cast_box::<_, String>(boxed) {
Ok(s) => return (*s).into(), Ok(s) => return (*s).into(),
Err(val) => val, Err(val) => val,
@ -384,6 +402,11 @@ impl Dynamic {
} }
} }
boxed = match unsafe_cast_box::<_, Dynamic>(boxed) {
Ok(d) => return *d,
Err(val) => val,
};
Self(Union::Variant(Box::new(boxed))) Self(Union::Variant(Box::new(boxed)))
} }
@ -401,30 +424,80 @@ impl Dynamic {
/// ///
/// assert_eq!(x.try_cast::<u32>().unwrap(), 42); /// assert_eq!(x.try_cast::<u32>().unwrap(), 42);
/// ``` /// ```
#[inline(always)]
pub fn try_cast<T: Variant>(self) -> Option<T> { pub fn try_cast<T: Variant>(self) -> Option<T> {
let type_id = TypeId::of::<T>(); let type_id = TypeId::of::<T>();
if type_id == TypeId::of::<INT>() {
return match self.0 {
Union::Int(value) => unsafe_try_cast(value),
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
if type_id == TypeId::of::<FLOAT>() {
return match self.0 {
Union::Float(value) => unsafe_try_cast(value),
_ => None,
};
}
if type_id == TypeId::of::<bool>() {
return match self.0 {
Union::Bool(value) => unsafe_try_cast(value),
_ => None,
};
}
if type_id == TypeId::of::<ImmutableString>() {
return match self.0 {
Union::Str(value) => unsafe_try_cast(value),
_ => None,
};
}
if type_id == TypeId::of::<String>() {
return match self.0 {
Union::Str(value) => unsafe_try_cast(value.into_owned()),
_ => None,
};
}
if type_id == TypeId::of::<char>() {
return match self.0 {
Union::Char(value) => unsafe_try_cast(value),
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
if type_id == TypeId::of::<Array>() {
return match self.0 {
Union::Array(value) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
_ => None,
};
}
#[cfg(not(feature = "no_object"))]
if type_id == TypeId::of::<Map>() {
return match self.0 {
Union::Map(value) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
_ => None,
};
}
if type_id == TypeId::of::<FnPtr>() {
return match self.0 {
Union::FnPtr(value) => unsafe_try_cast(value),
_ => None,
};
}
if type_id == TypeId::of::<()>() {
return match self.0 {
Union::Unit(value) => unsafe_try_cast(value),
_ => None,
};
}
if type_id == TypeId::of::<Dynamic>() { if type_id == TypeId::of::<Dynamic>() {
return unsafe_cast_box::<_, T>(Box::new(self)).ok().map(|v| *v); return unsafe_cast_box::<_, T>(Box::new(self)).ok().map(|v| *v);
} }
match self.0 { match self.0 {
Union::Unit(value) => unsafe_try_cast(value),
Union::Bool(value) => unsafe_try_cast(value),
Union::Str(value) if type_id == TypeId::of::<ImmutableString>() => {
unsafe_try_cast(value)
}
Union::Str(value) => unsafe_try_cast(value.into_owned()),
Union::Char(value) => unsafe_try_cast(value),
Union::Int(value) => unsafe_try_cast(value),
#[cfg(not(feature = "no_float"))]
Union::Float(value) => unsafe_try_cast(value),
#[cfg(not(feature = "no_index"))]
Union::Array(value) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
#[cfg(not(feature = "no_object"))]
Union::Map(value) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
Union::FnPtr(value) => unsafe_try_cast(value),
Union::Variant(value) => (*value).as_box_any().downcast().map(|x| *x).ok(), Union::Variant(value) => (*value).as_box_any().downcast().map(|x| *x).ok(),
_ => None,
} }
} }
@ -444,81 +517,162 @@ impl Dynamic {
/// ///
/// assert_eq!(x.cast::<u32>(), 42); /// assert_eq!(x.cast::<u32>(), 42);
/// ``` /// ```
#[inline(always)]
pub fn cast<T: Variant + Clone>(self) -> T { pub fn cast<T: Variant + Clone>(self) -> T {
let type_id = TypeId::of::<T>(); self.try_cast::<T>().unwrap()
if type_id == TypeId::of::<Dynamic>() {
return *unsafe_cast_box::<_, T>(Box::new(self)).unwrap();
}
match self.0 {
Union::Unit(value) => unsafe_try_cast(value).unwrap(),
Union::Bool(value) => unsafe_try_cast(value).unwrap(),
Union::Str(value) if type_id == TypeId::of::<ImmutableString>() => {
unsafe_try_cast(value).unwrap()
}
Union::Str(value) => unsafe_try_cast(value.into_owned()).unwrap(),
Union::Char(value) => unsafe_try_cast(value).unwrap(),
Union::Int(value) => unsafe_try_cast(value).unwrap(),
#[cfg(not(feature = "no_float"))]
Union::Float(value) => unsafe_try_cast(value).unwrap(),
#[cfg(not(feature = "no_index"))]
Union::Array(value) => *unsafe_cast_box::<_, T>(value).unwrap(),
#[cfg(not(feature = "no_object"))]
Union::Map(value) => *unsafe_cast_box::<_, T>(value).unwrap(),
Union::FnPtr(value) => unsafe_try_cast(value).unwrap(),
Union::Variant(value) => (*value).as_box_any().downcast().map(|x| *x).unwrap(),
}
} }
/// Get a reference of a specific type to the `Dynamic`. /// Get a reference of a specific type to the `Dynamic`.
/// Casting to `Dynamic` just returns a reference to it. /// Casting to `Dynamic` just returns a reference to it.
/// Returns `None` if the cast fails. /// Returns `None` if the cast fails.
#[inline(always)]
pub fn downcast_ref<T: Variant + Clone>(&self) -> Option<&T> { pub fn downcast_ref<T: Variant + Clone>(&self) -> Option<&T> {
if TypeId::of::<T>() == TypeId::of::<Dynamic>() { let type_id = TypeId::of::<T>();
if type_id == TypeId::of::<INT>() {
return match &self.0 {
Union::Int(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
if type_id == TypeId::of::<FLOAT>() {
return match &self.0 {
Union::Float(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<bool>() {
return match &self.0 {
Union::Bool(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<ImmutableString>() {
return match &self.0 {
Union::Str(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<String>() {
return match &self.0 {
Union::Str(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
if type_id == TypeId::of::<char>() {
return match &self.0 {
Union::Char(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
if type_id == TypeId::of::<Array>() {
return match &self.0 {
Union::Array(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
#[cfg(not(feature = "no_object"))]
if type_id == TypeId::of::<Map>() {
return match &self.0 {
Union::Map(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
_ => None,
};
}
if type_id == TypeId::of::<FnPtr>() {
return match &self.0 {
Union::FnPtr(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<()>() {
return match &self.0 {
Union::Unit(value) => <dyn Any>::downcast_ref::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<Dynamic>() {
return <dyn Any>::downcast_ref::<T>(self); return <dyn Any>::downcast_ref::<T>(self);
} }
match &self.0 { match &self.0 {
Union::Unit(value) => <dyn Any>::downcast_ref::<T>(value),
Union::Bool(value) => <dyn Any>::downcast_ref::<T>(value),
Union::Str(value) => <dyn Any>::downcast_ref::<T>(value)
.or_else(|| <dyn Any>::downcast_ref::<T>(value.as_ref())),
Union::Char(value) => <dyn Any>::downcast_ref::<T>(value),
Union::Int(value) => <dyn Any>::downcast_ref::<T>(value),
#[cfg(not(feature = "no_float"))]
Union::Float(value) => <dyn Any>::downcast_ref::<T>(value),
#[cfg(not(feature = "no_index"))]
Union::Array(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
#[cfg(not(feature = "no_object"))]
Union::Map(value) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
Union::FnPtr(value) => <dyn Any>::downcast_ref::<T>(value),
Union::Variant(value) => value.as_ref().as_ref().as_any().downcast_ref::<T>(), Union::Variant(value) => value.as_ref().as_ref().as_any().downcast_ref::<T>(),
_ => None,
} }
} }
/// Get a mutable reference of a specific type to the `Dynamic`. /// Get a mutable reference of a specific type to the `Dynamic`.
/// Casting to `Dynamic` just returns a mutable reference to it. /// Casting to `Dynamic` just returns a mutable reference to it.
/// Returns `None` if the cast fails. /// Returns `None` if the cast fails.
#[inline(always)]
pub fn downcast_mut<T: Variant + Clone>(&mut self) -> Option<&mut T> { pub fn downcast_mut<T: Variant + Clone>(&mut self) -> Option<&mut T> {
if TypeId::of::<T>() == TypeId::of::<Dynamic>() { let type_id = TypeId::of::<T>();
if type_id == TypeId::of::<INT>() {
return match &mut self.0 {
Union::Int(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_float"))]
if type_id == TypeId::of::<FLOAT>() {
return match &mut self.0 {
Union::Float(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<bool>() {
return match &mut self.0 {
Union::Bool(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<ImmutableString>() {
return match &mut self.0 {
Union::Str(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<char>() {
return match &mut self.0 {
Union::Char(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
#[cfg(not(feature = "no_index"))]
if type_id == TypeId::of::<Array>() {
return match &mut self.0 {
Union::Array(value) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
#[cfg(not(feature = "no_object"))]
if type_id == TypeId::of::<Map>() {
return match &mut self.0 {
Union::Map(value) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
_ => None,
};
}
if type_id == TypeId::of::<FnPtr>() {
return match &mut self.0 {
Union::FnPtr(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<()>() {
return match &mut self.0 {
Union::Unit(value) => <dyn Any>::downcast_mut::<T>(value),
_ => None,
};
}
if type_id == TypeId::of::<Dynamic>() {
return <dyn Any>::downcast_mut::<T>(self); return <dyn Any>::downcast_mut::<T>(self);
} }
match &mut self.0 { match &mut self.0 {
Union::Unit(value) => <dyn Any>::downcast_mut::<T>(value),
Union::Bool(value) => <dyn Any>::downcast_mut::<T>(value),
Union::Str(value) => <dyn Any>::downcast_mut::<T>(value),
Union::Char(value) => <dyn Any>::downcast_mut::<T>(value),
Union::Int(value) => <dyn Any>::downcast_mut::<T>(value),
#[cfg(not(feature = "no_float"))]
Union::Float(value) => <dyn Any>::downcast_mut::<T>(value),
#[cfg(not(feature = "no_index"))]
Union::Array(value) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
#[cfg(not(feature = "no_object"))]
Union::Map(value) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
Union::FnPtr(value) => <dyn Any>::downcast_mut::<T>(value),
Union::Variant(value) => value.as_mut().as_mut_any().downcast_mut::<T>(), Union::Variant(value) => value.as_mut().as_mut_any().downcast_mut::<T>(),
_ => None,
} }
} }

View File

@ -12,6 +12,7 @@ use crate::stdlib::{
}; };
/// Cast a type into another type. /// Cast a type into another type.
#[inline(always)]
pub fn unsafe_try_cast<A: Any, B: Any>(a: A) -> Option<B> { pub fn unsafe_try_cast<A: Any, B: Any>(a: A) -> Option<B> {
if TypeId::of::<B>() == a.type_id() { if TypeId::of::<B>() == a.type_id() {
// SAFETY: Just checked we have the right type. We explicitly forget the // SAFETY: Just checked we have the right type. We explicitly forget the
@ -28,6 +29,7 @@ pub fn unsafe_try_cast<A: Any, B: Any>(a: A) -> Option<B> {
} }
/// Cast a Boxed type into another type. /// Cast a Boxed type into another type.
#[inline(always)]
pub fn unsafe_cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<Box<T>, Box<X>> { pub fn unsafe_cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<Box<T>, Box<X>> {
// Only allow casting to the exact same type // Only allow casting to the exact same type
if TypeId::of::<X>() == TypeId::of::<T>() { if TypeId::of::<X>() == TypeId::of::<T>() {
@ -51,6 +53,7 @@ pub fn unsafe_cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<Box<T>, B
/// ///
/// Force-casting a local variable's lifetime to the current `Scope`'s larger lifetime saves /// Force-casting a local variable's lifetime to the current `Scope`'s larger lifetime saves
/// on allocations and string cloning, thus avoids us having to maintain a chain of `Scope`'s. /// on allocations and string cloning, thus avoids us having to maintain a chain of `Scope`'s.
#[inline]
pub fn unsafe_cast_var_name_to_lifetime<'s>(name: &str, state: &State) -> Cow<'s, str> { pub fn unsafe_cast_var_name_to_lifetime<'s>(name: &str, state: &State) -> Cow<'s, str> {
// If not at global level, we can force-cast // If not at global level, we can force-cast
if state.scope_level > 0 { if state.scope_level > 0 {

View File

@ -36,11 +36,9 @@ use ahash::AHasher;
pub struct StraightHasher(u64); pub struct StraightHasher(u64);
impl Hasher for StraightHasher { impl Hasher for StraightHasher {
#[inline(always)]
fn finish(&self) -> u64 { fn finish(&self) -> u64 {
self.0 self.0
} }
#[inline]
fn write(&mut self, bytes: &[u8]) { fn write(&mut self, bytes: &[u8]) {
let mut key = [0_u8; 8]; let mut key = [0_u8; 8];
key.copy_from_slice(&bytes[..8]); // Panics if fewer than 8 bytes key.copy_from_slice(&bytes[..8]); // Panics if fewer than 8 bytes
@ -50,7 +48,6 @@ impl Hasher for StraightHasher {
impl StraightHasher { impl StraightHasher {
/// Create a `StraightHasher`. /// Create a `StraightHasher`.
#[inline(always)]
pub fn new() -> Self { pub fn new() -> Self {
Self(0) Self(0)
} }
@ -63,7 +60,6 @@ pub struct StraightHasherBuilder;
impl BuildHasher for StraightHasherBuilder { impl BuildHasher for StraightHasherBuilder {
type Hasher = StraightHasher; type Hasher = StraightHasher;
#[inline(always)]
fn build_hasher(&self) -> Self::Hasher { fn build_hasher(&self) -> Self::Hasher {
StraightHasher::new() StraightHasher::new()
} }
@ -150,7 +146,6 @@ pub struct StaticVec<T> {
const MAX_STATIC_VEC: usize = 4; const MAX_STATIC_VEC: usize = 4;
impl<T> Drop for StaticVec<T> { impl<T> Drop for StaticVec<T> {
#[inline(always)]
fn drop(&mut self) { fn drop(&mut self) {
self.clear(); self.clear();
} }
@ -233,7 +228,6 @@ impl<T: 'static> IntoIterator for StaticVec<T> {
impl<T> StaticVec<T> { impl<T> StaticVec<T> {
/// Create a new `StaticVec`. /// Create a new `StaticVec`.
#[inline(always)]
pub fn new() -> Self { pub fn new() -> Self {
Default::default() Default::default()
} }
@ -249,7 +243,6 @@ impl<T> StaticVec<T> {
self.len = 0; self.len = 0;
} }
/// Extract a `MaybeUninit` into a concrete initialized type. /// Extract a `MaybeUninit` into a concrete initialized type.
#[inline(always)]
fn extract(value: MaybeUninit<T>) -> T { fn extract(value: MaybeUninit<T>) -> T {
unsafe { value.assume_init() } unsafe { value.assume_init() }
} }
@ -311,7 +304,6 @@ impl<T> StaticVec<T> {
); );
} }
/// Is data stored in fixed-size storage? /// Is data stored in fixed-size storage?
#[inline(always)]
fn is_fixed_storage(&self) -> bool { fn is_fixed_storage(&self) -> bool {
self.len <= MAX_STATIC_VEC self.len <= MAX_STATIC_VEC
} }
@ -418,12 +410,10 @@ impl<T> StaticVec<T> {
} }
} }
/// Get the number of items in this `StaticVec`. /// Get the number of items in this `StaticVec`.
#[inline(always)]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.len self.len
} }
/// Is this `StaticVec` empty? /// Is this `StaticVec` empty?
#[inline(always)]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.len == 0 self.len == 0
} }
@ -664,48 +654,41 @@ pub struct ImmutableString(Shared<String>);
impl Deref for ImmutableString { impl Deref for ImmutableString {
type Target = String; type Target = String;
#[inline(always)]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.0
} }
} }
impl AsRef<String> for ImmutableString { impl AsRef<String> for ImmutableString {
#[inline(always)]
fn as_ref(&self) -> &String { fn as_ref(&self) -> &String {
&self.0 &self.0
} }
} }
impl Borrow<str> for ImmutableString { impl Borrow<str> for ImmutableString {
#[inline(always)]
fn borrow(&self) -> &str { fn borrow(&self) -> &str {
self.0.as_str() self.0.as_str()
} }
} }
impl From<&str> for ImmutableString { impl From<&str> for ImmutableString {
#[inline(always)]
fn from(value: &str) -> Self { fn from(value: &str) -> Self {
Self(value.to_string().into()) Self(value.to_string().into())
} }
} }
impl From<String> for ImmutableString { impl From<String> for ImmutableString {
#[inline(always)]
fn from(value: String) -> Self { fn from(value: String) -> Self {
Self(value.into()) Self(value.into())
} }
} }
impl From<Box<String>> for ImmutableString { impl From<Box<String>> for ImmutableString {
#[inline(always)]
fn from(value: Box<String>) -> Self { fn from(value: Box<String>) -> Self {
Self(value.into()) Self(value.into())
} }
} }
impl From<ImmutableString> for String { impl From<ImmutableString> for String {
#[inline(always)]
fn from(value: ImmutableString) -> Self { fn from(value: ImmutableString) -> Self {
value.into_owned() value.into_owned()
} }
@ -714,49 +697,42 @@ impl From<ImmutableString> for String {
impl FromStr for ImmutableString { impl FromStr for ImmutableString {
type Err = (); type Err = ();
#[inline(always)]
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(s.to_string().into())) Ok(Self(s.to_string().into()))
} }
} }
impl FromIterator<char> for ImmutableString { impl FromIterator<char> for ImmutableString {
#[inline(always)]
fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
Self(iter.into_iter().collect::<String>().into()) Self(iter.into_iter().collect::<String>().into())
} }
} }
impl<'a> FromIterator<&'a char> for ImmutableString { impl<'a> FromIterator<&'a char> for ImmutableString {
#[inline(always)]
fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
Self(iter.into_iter().cloned().collect::<String>().into()) Self(iter.into_iter().cloned().collect::<String>().into())
} }
} }
impl<'a> FromIterator<&'a str> for ImmutableString { impl<'a> FromIterator<&'a str> for ImmutableString {
#[inline(always)]
fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
Self(iter.into_iter().collect::<String>().into()) Self(iter.into_iter().collect::<String>().into())
} }
} }
impl<'a> FromIterator<String> for ImmutableString { impl<'a> FromIterator<String> for ImmutableString {
#[inline(always)]
fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
Self(iter.into_iter().collect::<String>().into()) Self(iter.into_iter().collect::<String>().into())
} }
} }
impl fmt::Display for ImmutableString { impl fmt::Display for ImmutableString {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.0.as_str(), f) fmt::Display::fmt(self.0.as_str(), f)
} }
} }
impl fmt::Debug for ImmutableString { impl fmt::Debug for ImmutableString {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.0.as_str(), f) fmt::Debug::fmt(self.0.as_str(), f)
} }
@ -891,7 +867,6 @@ impl Add<char> for &ImmutableString {
} }
impl AddAssign<char> for ImmutableString { impl AddAssign<char> for ImmutableString {
#[inline(always)]
fn add_assign(&mut self, rhs: char) { fn add_assign(&mut self, rhs: char) {
self.make_mut().push(rhs); self.make_mut().push(rhs);
} }
@ -906,7 +881,6 @@ impl ImmutableString {
} }
/// Make sure that the `ImmutableString` is unique (i.e. no other outstanding references). /// Make sure that the `ImmutableString` is unique (i.e. no other outstanding references).
/// Then return a mutable reference to the `String`. /// Then return a mutable reference to the `String`.
#[inline(always)]
pub fn make_mut(&mut self) -> &mut String { pub fn make_mut(&mut self) -> &mut String {
shared_make_mut(&mut self.0) shared_make_mut(&mut self.0)
} }