git2/
string_array.rs

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