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
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ffi::{CStr, CString};
use sys;

/// A list of strings.
#[derive(Debug)]
pub struct SBStringList {
    /// The underlying raw `SBStringListRef`.
    pub raw: sys::SBStringListRef,
}

impl SBStringList {
    /// Construct a new `SBStringList`.
    pub fn new() -> SBStringList {
        SBStringList::wrap(unsafe { sys::CreateSBStringList() })
    }
    /// Construct a new `SBStringList`.
    pub fn wrap(raw: sys::SBStringListRef) -> SBStringList {
        SBStringList { raw: raw }
    }

    /// Construct a new `Some(SBStringList)` or `None`.
    pub fn maybe_wrap(raw: sys::SBStringListRef) -> Option<SBStringList> {
        if unsafe { sys::SBStringListIsValid(raw) != 0 } {
            Some(SBStringList { raw: raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBStringList` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBStringListIsValid(self.raw) != 0 }
    }

    /// Is this string list empty?
    pub fn is_empty(&self) -> bool {
        unsafe { sys::SBStringListGetSize(self.raw) == 0 }
    }

    /// Clear this string list.
    pub fn clear(&self) {
        unsafe { sys::SBStringListClear(self.raw) };
    }

    /// Append another string to this list.
    pub fn append_string(&self, string: &str) {
        let string = CString::new(string).unwrap();
        unsafe { sys::SBStringListAppendString(self.raw, string.as_ptr()) };
    }

    /// Append another string list to this one.
    pub fn append_list(&self, other: &SBStringList) {
        unsafe { sys::SBStringListAppendList2(self.raw, other.raw) };
    }

    /// Iterate over this string list.
    pub fn iter(&self) -> SBStringListIter {
        SBStringListIter {
            string_list: self,
            idx: 0,
        }
    }
}

impl Default for SBStringList {
    fn default() -> Self {
        Self::new()
    }
}

impl Drop for SBStringList {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBStringList(self.raw) };
    }
}

/// An iterator over an `SBStringList`.
pub struct SBStringListIter<'d> {
    string_list: &'d SBStringList,
    idx: usize,
}

impl<'d> Iterator for SBStringListIter<'d> {
    type Item = &'d str;

    fn next(&mut self) -> Option<&'d str> {
        if self.idx < unsafe { sys::SBStringListGetSize(self.string_list.raw) as usize } {
            let r = unsafe {
                match CStr::from_ptr(sys::SBStringListGetStringAtIndex(
                    self.string_list.raw,
                    self.idx,
                )).to_str() {
                    Ok(s) => s,
                    _ => panic!("Invalid string?"),
                }
            };
            self.idx += 1;
            Some(r)
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let sz = unsafe { sys::SBStringListGetSize(self.string_list.raw) } as usize;
        (sz - self.idx, Some(sz))
    }
}