use libedit_sys::*;
use std::ffi::{CStr, CString};
use std::ptr;
use crate::error::{Error, Result};
pub struct Tokenizer {
inner: *mut libedit_sys::Tokenizer,
}
impl Tokenizer {
pub fn new(separators: Option<&str>) -> Result<Self> {
if let Some(s) = separators {
if !s.is_ascii() {
return Err(Error::operation(0, -1));
}
}
let sep = match separators {
Some(s) => Some(CString::new(s)?),
None => None,
};
let inner = unsafe {
match &sep {
Some(s) => tok_init(s.as_ptr()),
None => tok_init(ptr::null()),
}
};
if inner.is_null() {
return Err(Error::operation(0, -1));
}
Ok(Tokenizer { inner })
}
pub fn tokenize(&mut self, input: impl Into<String>) -> Result<Vec<&str>> {
let c_input = CString::new(input.into())?;
let mut argc: i32 = 0;
let mut argv: *mut *const std::os::raw::c_char = ptr::null_mut();
let ret = unsafe { tok_str(self.inner, c_input.as_ptr(), &mut argc, &mut argv) };
if ret != 0 {
return Err(Error::operation(0, ret));
}
let mut words = Vec::with_capacity(argc as usize);
for i in 0..argc {
let word = unsafe { CStr::from_ptr(*argv.offset(i as isize)) };
words.push(
word.to_str().expect(
"tokenizer produced non-UTF-8 despite String input and ASCII separators",
),
);
}
Ok(words)
}
pub fn reset(&mut self) {
unsafe { tok_reset(self.inner) };
}
}
impl Drop for Tokenizer {
fn drop(&mut self) {
unsafe { tok_end(self.inner) };
}
}