Skip to main content

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