1 //! Bindings to libgit2's raw `git_strarray` type
2 
3 use std::ops::Range;
4 use std::str;
5 
6 use crate::raw;
7 use crate::util::Binding;
8 
9 /// A string array structure used by libgit2
10 ///
11 /// Some apis return arrays of strings which originate from libgit2. This
12 /// wrapper type behaves a little like `Vec<&str>` but does so without copying
13 /// the underlying strings until necessary.
14 pub struct StringArray {
15     raw: raw::git_strarray,
16 }
17 
18 /// A forward iterator over the strings of an array, casted to `&str`.
19 pub struct Iter<'a> {
20     range: Range<usize>,
21     arr: &'a StringArray,
22 }
23 
24 /// A forward iterator over the strings of an array, casted to `&[u8]`.
25 pub struct IterBytes<'a> {
26     range: Range<usize>,
27     arr: &'a StringArray,
28 }
29 
30 impl StringArray {
31     /// Returns None if the i'th string is not utf8 or if i is out of bounds.
get(&self, i: usize) -> Option<&str>32     pub fn get(&self, i: usize) -> Option<&str> {
33         self.get_bytes(i).and_then(|s| str::from_utf8(s).ok())
34     }
35 
36     /// Returns None if `i` is out of bounds.
get_bytes(&self, i: usize) -> Option<&[u8]>37     pub fn get_bytes(&self, i: usize) -> Option<&[u8]> {
38         if i < self.raw.count as usize {
39             unsafe {
40                 let ptr = *self.raw.strings.add(i) as *const _;
41                 Some(crate::opt_bytes(self, ptr).unwrap())
42             }
43         } else {
44             None
45         }
46     }
47 
48     /// Returns an iterator over the strings contained within this array.
49     ///
50     /// The iterator yields `Option<&str>` as it is unknown whether the contents
51     /// are utf-8 or not.
iter(&self) -> Iter<'_>52     pub fn iter(&self) -> Iter<'_> {
53         Iter {
54             range: 0..self.len(),
55             arr: self,
56         }
57     }
58 
59     /// Returns an iterator over the strings contained within this array,
60     /// yielding byte slices.
iter_bytes(&self) -> IterBytes<'_>61     pub fn iter_bytes(&self) -> IterBytes<'_> {
62         IterBytes {
63             range: 0..self.len(),
64             arr: self,
65         }
66     }
67 
68     /// Returns the number of strings in this array.
len(&self) -> usize69     pub fn len(&self) -> usize {
70         self.raw.count as usize
71     }
72 
73     /// Return `true` if this array is empty.
is_empty(&self) -> bool74     pub fn is_empty(&self) -> bool {
75         self.len() == 0
76     }
77 }
78 
79 impl Binding for StringArray {
80     type Raw = raw::git_strarray;
from_raw(raw: raw::git_strarray) -> StringArray81     unsafe fn from_raw(raw: raw::git_strarray) -> StringArray {
82         StringArray { raw }
83     }
raw(&self) -> raw::git_strarray84     fn raw(&self) -> raw::git_strarray {
85         self.raw
86     }
87 }
88 
89 impl<'a> IntoIterator for &'a StringArray {
90     type Item = Option<&'a str>;
91     type IntoIter = Iter<'a>;
into_iter(self) -> Self::IntoIter92     fn into_iter(self) -> Self::IntoIter {
93         self.iter()
94     }
95 }
96 
97 impl<'a> Iterator for Iter<'a> {
98     type Item = Option<&'a str>;
next(&mut self) -> Option<Option<&'a str>>99     fn next(&mut self) -> Option<Option<&'a str>> {
100         self.range.next().map(|i| self.arr.get(i))
101     }
size_hint(&self) -> (usize, Option<usize>)102     fn size_hint(&self) -> (usize, Option<usize>) {
103         self.range.size_hint()
104     }
105 }
106 impl<'a> DoubleEndedIterator for Iter<'a> {
next_back(&mut self) -> Option<Option<&'a str>>107     fn next_back(&mut self) -> Option<Option<&'a str>> {
108         self.range.next_back().map(|i| self.arr.get(i))
109     }
110 }
111 impl<'a> ExactSizeIterator for Iter<'a> {}
112 
113 impl<'a> Iterator for IterBytes<'a> {
114     type Item = &'a [u8];
next(&mut self) -> Option<&'a [u8]>115     fn next(&mut self) -> Option<&'a [u8]> {
116         self.range.next().and_then(|i| self.arr.get_bytes(i))
117     }
size_hint(&self) -> (usize, Option<usize>)118     fn size_hint(&self) -> (usize, Option<usize>) {
119         self.range.size_hint()
120     }
121 }
122 impl<'a> DoubleEndedIterator for IterBytes<'a> {
next_back(&mut self) -> Option<&'a [u8]>123     fn next_back(&mut self) -> Option<&'a [u8]> {
124         self.range.next_back().and_then(|i| self.arr.get_bytes(i))
125     }
126 }
127 impl<'a> ExactSizeIterator for IterBytes<'a> {}
128 
129 impl Drop for StringArray {
drop(&mut self)130     fn drop(&mut self) {
131         unsafe { raw::git_strarray_free(&mut self.raw) }
132     }
133 }
134