1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#![deny(missing_docs)]

//! This crate provides two owned iterators over String: OwnedChars and OwnedCharIndices. They have
//! the same output as Chars and CharIndices, but creating the iterator consumes the String as
//! opposed to borrowing.
//! 
//! Do you think this should be included in Rust proper? [Comment
//! here](https://github.com/durka/owned-chars/issues/5) if so!

#[macro_use]
extern crate delegate;

/// Extension trait for String providing owned char and char-index iterators
pub trait OwnedCharsExt {
    /// Gets an owning iterator over the chars (see `chars()`)
    fn into_chars(self) -> OwnedChars;
    /// Gets an owning iterator over the chars and their indices (see `char_indices()`)
    fn into_char_indices(self) -> OwnedCharIndices;
}

impl OwnedCharsExt for String {
    fn into_chars(self) -> OwnedChars {
        OwnedChars::from_string(self)
    }

    fn into_char_indices(self) -> OwnedCharIndices {
        OwnedCharIndices::from_string(self)
    }
}

/// structs
mod structs {
    use std::str::{Chars, CharIndices};
    use std::iter::{Iterator, DoubleEndedIterator, FusedIterator};
    use std::mem::transmute;

    /// Iterator over the chars of a string (the string is owned by the iterator)
    #[derive(Debug)]
    pub struct OwnedChars {
        s: String,
        i: Chars<'static>,
    }

    /// Iterator over the chars of a string and their indices (the string is owned by the iterator)
    #[derive(Debug)]
    pub struct OwnedCharIndices {
        s: String,
        i: CharIndices<'static>,
    }

    macro_rules! impls {
        ($owned_struct:ident, $target_struct:ident, $method: ident, $item: ty) => {
            impl $owned_struct {
                /// Create Self from a String, moving the String into Self
                pub fn from_string(s: String) -> Self {
                    unsafe {
                        // First, we can call .chars/.char_indices, whose result will have the same
                        // lifetime as the owner. We need the transmute to "widen" the lifetime into
                        // 'static which allows us to store it in the struct.
                        //
                        // The struct fields are private, so users can't observe this fake static
                        // lifetime. Code within this module must never destructure the struct
                        // because it risks losing track of the real lifetime!
                        let i = transmute::<$target_struct, $target_struct<'static>>(s.$method());

                        // Now, move the string (but not the string data!)
                        $owned_struct { s, i }
                    }
                }

                /// Consume this struct and return the contained String
                pub fn into_inner(self) -> String {
                    self.s
                }

                delegate! {
                    to self.i {
                        /// Borrow the contained String
                        pub fn as_str(&self) -> &str;
                    }
                }
            }

            impl Iterator for $owned_struct {
                type Item = $item;

                delegate! {
                    to self.i {
                        fn next(&mut self) -> Option<$item>;
                        fn count(self) -> usize;
                        fn size_hint(&self) -> (usize, Option<usize>);
                        fn last(self) -> Option<$item>;
                    }
                }
            }

            impl DoubleEndedIterator for $owned_struct {
                delegate! {
                    to self.i {
                        fn next_back(&mut self) -> Option<$item>;
                    }
                }
            }

            impl FusedIterator for $owned_struct {}
        };
    }

    impls!(OwnedChars, Chars, chars, char);
    impls!(OwnedCharIndices, CharIndices, char_indices, (usize, char));
}

pub use structs::*;

#[test]
fn chars() {
    let s = String::from("héllo");
    assert_eq!(s.chars().collect::<Vec<_>>(),
               s.into_chars().collect::<Vec<_>>());
}

#[test]
fn unicode() {
    let s = String::from("héllo");
    assert_eq!(Some('é'), s.clone().into_chars().skip(1).next());
    assert_eq!(Some('l'), s.clone().into_chars().skip(2).next());
}

#[test]
fn char_indices() {
    let s = String::from("héllo");
    assert_eq!(s.char_indices().collect::<Vec<_>>(),
               s.into_char_indices().collect::<Vec<_>>());
}

#[test]
fn methods() {
    let s = String::from("héllo");
    let oc = s.clone().into_chars();
    let oci = s.clone().into_char_indices();
    assert_eq!(&s, oc.as_str());
    assert_eq!(&s, oci.as_str());
    assert_eq!(s, oc.into_inner());
    assert_eq!(s, oci.into_inner());
}