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