std: create Str trait for DRY. Use it on StrVector.
The Str trait collects the various strings types and provides a method for coercing to a slice, so that functions and impls can be written for generic types containing strings (e.g. &[~str], &[&str], ...) without having to write one for each string type (assuming that the impl only needs a slice).
This commit is contained in:
parent
3a1e13c7a0
commit
073e82fff2
|
@ -26,7 +26,7 @@ use clone::Clone;
|
||||||
use cmp::{TotalOrd, Ordering, Less, Equal, Greater};
|
use cmp::{TotalOrd, Ordering, Less, Equal, Greater};
|
||||||
use container::Container;
|
use container::Container;
|
||||||
use iter::Times;
|
use iter::Times;
|
||||||
use iterator::{Iterator, IteratorUtil, FilterIterator};
|
use iterator::{Iterator, IteratorUtil, FilterIterator, AdditiveIterator};
|
||||||
use libc;
|
use libc;
|
||||||
use option::{None, Option, Some};
|
use option::{None, Option, Some};
|
||||||
use old_iter::{BaseIter, EqIter};
|
use old_iter::{BaseIter, EqIter};
|
||||||
|
@ -160,15 +160,13 @@ pub trait StrVector {
|
||||||
pub fn connect(&self, sep: &str) -> ~str;
|
pub fn connect(&self, sep: &str) -> ~str;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> StrVector for &'self [~str] {
|
impl<'self, S: Str> StrVector for &'self [S] {
|
||||||
/// Concatenate a vector of strings.
|
/// Concatenate a vector of strings.
|
||||||
pub fn concat(&self) -> ~str {
|
pub fn concat(&self) -> ~str {
|
||||||
if self.is_empty() { return ~""; }
|
if self.is_empty() { return ~""; }
|
||||||
|
|
||||||
let mut len = 0;
|
let len = self.iter().transform(|s| s.as_slice().len()).sum();
|
||||||
for self.each |ss| {
|
|
||||||
len += ss.len();
|
|
||||||
}
|
|
||||||
let mut s = ~"";
|
let mut s = ~"";
|
||||||
|
|
||||||
s.reserve(len);
|
s.reserve(len);
|
||||||
|
@ -176,8 +174,8 @@ impl<'self> StrVector for &'self [~str] {
|
||||||
unsafe {
|
unsafe {
|
||||||
do as_buf(s) |buf, _| {
|
do as_buf(s) |buf, _| {
|
||||||
let mut buf = ::cast::transmute_mut_unsafe(buf);
|
let mut buf = ::cast::transmute_mut_unsafe(buf);
|
||||||
for self.each |ss| {
|
for self.iter().advance |ss| {
|
||||||
do as_buf(*ss) |ssbuf, sslen| {
|
do as_buf(ss.as_slice()) |ssbuf, sslen| {
|
||||||
let sslen = sslen - 1;
|
let sslen = sslen - 1;
|
||||||
ptr::copy_memory(buf, ssbuf, sslen);
|
ptr::copy_memory(buf, ssbuf, sslen);
|
||||||
buf = buf.offset(sslen);
|
buf = buf.offset(sslen);
|
||||||
|
@ -197,10 +195,8 @@ impl<'self> StrVector for &'self [~str] {
|
||||||
if sep.is_empty() { return self.concat(); }
|
if sep.is_empty() { return self.concat(); }
|
||||||
|
|
||||||
// this is wrong without the guarantee that `self` is non-empty
|
// this is wrong without the guarantee that `self` is non-empty
|
||||||
let mut len = sep.len() * (self.len() - 1);
|
let len = sep.len() * (self.len() - 1)
|
||||||
for self.each |ss| {
|
+ self.iter().transform(|s| s.as_slice().len()).sum();
|
||||||
len += ss.len();
|
|
||||||
}
|
|
||||||
let mut s = ~"";
|
let mut s = ~"";
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
|
|
||||||
|
@ -211,80 +207,8 @@ impl<'self> StrVector for &'self [~str] {
|
||||||
do as_buf(sep) |sepbuf, seplen| {
|
do as_buf(sep) |sepbuf, seplen| {
|
||||||
let seplen = seplen - 1;
|
let seplen = seplen - 1;
|
||||||
let mut buf = ::cast::transmute_mut_unsafe(buf);
|
let mut buf = ::cast::transmute_mut_unsafe(buf);
|
||||||
for self.each |ss| {
|
for self.iter().advance |ss| {
|
||||||
do as_buf(*ss) |ssbuf, sslen| {
|
do as_buf(ss.as_slice()) |ssbuf, sslen| {
|
||||||
let sslen = sslen - 1;
|
|
||||||
if first {
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
ptr::copy_memory(buf, sepbuf, seplen);
|
|
||||||
buf = buf.offset(seplen);
|
|
||||||
}
|
|
||||||
ptr::copy_memory(buf, ssbuf, sslen);
|
|
||||||
buf = buf.offset(sslen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
raw::set_len(&mut s, len);
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'self> StrVector for &'self [&'self str] {
|
|
||||||
/// Concatenate a vector of strings.
|
|
||||||
pub fn concat(&self) -> ~str {
|
|
||||||
if self.is_empty() { return ~""; }
|
|
||||||
|
|
||||||
let mut len = 0;
|
|
||||||
for self.each |ss| {
|
|
||||||
len += ss.len();
|
|
||||||
}
|
|
||||||
let mut s = ~"";
|
|
||||||
|
|
||||||
s.reserve(len);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
do as_buf(s) |buf, _| {
|
|
||||||
let mut buf = ::cast::transmute_mut_unsafe(buf);
|
|
||||||
for self.each |ss| {
|
|
||||||
do as_buf(*ss) |ssbuf, sslen| {
|
|
||||||
let sslen = sslen - 1;
|
|
||||||
ptr::copy_memory(buf, ssbuf, sslen);
|
|
||||||
buf = buf.offset(sslen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
raw::set_len(&mut s, len);
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Concatenate a vector of strings, placing a given separator between each.
|
|
||||||
pub fn connect(&self, sep: &str) -> ~str {
|
|
||||||
if self.is_empty() { return ~""; }
|
|
||||||
|
|
||||||
// concat is faster
|
|
||||||
if sep.is_empty() { return self.concat(); }
|
|
||||||
|
|
||||||
// this is wrong without the guarantee that `self` is non-empty
|
|
||||||
let mut len = sep.len() * (self.len() - 1);
|
|
||||||
for self.each |ss| {
|
|
||||||
len += ss.len();
|
|
||||||
}
|
|
||||||
let mut s = ~"";
|
|
||||||
let mut first = true;
|
|
||||||
|
|
||||||
s.reserve(len);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
do as_buf(s) |buf, _| {
|
|
||||||
do as_buf(sep) |sepbuf, seplen| {
|
|
||||||
let seplen = seplen - 1;
|
|
||||||
let mut buf = ::cast::transmute_mut_unsafe(buf);
|
|
||||||
for self.each |ss| {
|
|
||||||
do as_buf(*ss) |ssbuf, sslen| {
|
|
||||||
let sslen = sslen - 1;
|
let sslen = sslen - 1;
|
||||||
if first {
|
if first {
|
||||||
first = false;
|
first = false;
|
||||||
|
@ -1267,6 +1191,29 @@ pub mod traits {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod traits {}
|
pub mod traits {}
|
||||||
|
|
||||||
|
/// Any string that can be represented as a slice
|
||||||
|
pub trait Str {
|
||||||
|
/// Work with `self` as a slice.
|
||||||
|
fn as_slice<'a>(&'a self) -> &'a str;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'self> Str for &'self str {
|
||||||
|
#[inline(always)]
|
||||||
|
fn as_slice<'a>(&'a self) -> &'a str { *self }
|
||||||
|
}
|
||||||
|
impl<'self> Str for ~str {
|
||||||
|
#[inline(always)]
|
||||||
|
fn as_slice<'a>(&'a self) -> &'a str {
|
||||||
|
let s: &'a str = *self; s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'self> Str for @str {
|
||||||
|
#[inline(always)]
|
||||||
|
fn as_slice<'a>(&'a self) -> &'a str {
|
||||||
|
let s: &'a str = *self; s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(missing_doc)]
|
#[allow(missing_doc)]
|
||||||
pub trait StrSlice<'self> {
|
pub trait StrSlice<'self> {
|
||||||
fn contains<'a>(&self, needle: &'a str) -> bool;
|
fn contains<'a>(&self, needle: &'a str) -> bool;
|
||||||
|
|
Loading…
Reference in New Issue